nodeでガラケー対応したメモ
Webサービス的なものをnodeでつくってて、ガラケー対応しないといけないことはわかってたんだけど、しばらくガラケー対応とかやってなかったので、すっかり文字コードのことを忘れてて痛い目みた。
ガラケーだけPHPかPerlで書こうと思ったけど、そんなに大きいアプリじゃないのでできればPCとガラケーのロジック同じにしたかったので頑張ってみた。
入力は全部SJISからUTF-8に変換して、出力はUTF-8からSJISに変換する。内部では全てUTF-8としてデータを扱う。一部のSoftBank端末がSJISで問題あるからUTF-8がいいとかはこの際気にしない。
まず端末を判定するところ。
app.use(function(req, res, next) { var ua = req.headers['user-agent']; var regexp = /^(DoCoMo|KDDI|Up\.Browser|J-PHONE|vodafone|SoftBank)/i; req.isMobile = regexp.test(ua); req.encoding = req.isMobile ? 'shift_jis' : 'utf8'; next(); });
まあ判定ロジックは手抜きにしたので簡単。
次に出力をSJISにする。これはrenderするところでiconv使ってutf8をshift_jisに変換する。
var Iconv = require('iconv').Iconv; var iconv = new Iconv('utf-8', 'shift_jis'); ... if (req.isMobile) { // ガラケーの時の処理 res.render('m/' + tmpl, data, function(err, html) { res.header('Content-Type', 'text/html; charset=shift_jis'); res.send(iconv.convert(html)); }); } else { // 普通のPCの処理 res.render(tmpl, data); }
(iconvのインスタンスつくるのはコールバックの中のほうがいいかもとのこと。コメント欄参照)
こんな感じ。expressの第三引数にコールバックを指定するとrender結果を受け取れるということがわかったので、割とキレイに実装できた。
問題は入力。POSTで受け取ったリクエストbodyをパースするところで、connectのbodyParserはdecodeURIComponentを使っていて、これがSJISに対応してないのでSJISでPOSTするとエラる。
これはブラウザのJavaScriptで同じ問題らしく、SJISのパーセントエンコーディングをデコードしてくれるやつがあった。
http://travel.han-be.com/ecl/Escape%20Codec%20Library%20ecl_js.htm
ecl.js (Escape Codec Library) と Sleipnir の相性が悪い件について - drk7jp
これでSJISのデコードができるので、decodeURIComponentを使ってたところで
var decoder = encoding === 'shift_jis' ? unescapeSJIS : decodeURIComponent;
とかして、エンコーディングを渡してshift_jisだったらelc.jsのやつを使ってデコードするとかした。手を入れたのはconnect/middleware/bodyParser と qs。
これで何とか対応できたけどまあとりあえず今後はガラケー対応はnodeじゃやらない。