Life goes on

何かJavaScriptとかVimとかMacとかに関係してそうな深淵から覗かれる者

iOS6のPOSTの改修をjQueryでやったら、何かハマった

まあ表題の通りなんですが。先日書いた記事のおかげでiOS6 バグとかのキーワードでこのブログ見る人が 多いようです。みなさんも苦労されてるんだなーとしみじみと他人事のように思ってたら、自分も対応する事になりました。 罰ですね。

jQuery使ってて、iOS6だけでAjax使用時にPOSTがキャッシュされるという例のアレの対応です。色々あってこちらを 参照に$.ajax()のPOST時にタイムスタンプ付けて対応しました。今回は案件で共通で使ってるAjaxのラッパーがあるのでそちらの呼び出しの前に設定しておきまして、 不具合も無くなり、「やれやれだぜ…」と思っていました。

そしたら、あるページで通信エラーが出るじゃありませんか。原因調べてみると上記の対応で起ったというか、jQueryに頼り過ぎたというか…というものでした。

そのページでは、最初のAjax使ってのPOST時にはあるパラメーターがundefinedになっており、2回目のPOST時にはそのパラメーターに値が入るという実装になってました。 $.ajax()では何も考えず、最初のundefined入ってるパラメーターを渡しても送信しなかったのですが、今回の対応により、タイムスタンプと共にundefinedという文字列が 入ったパラメーターを送信してしまうようになってました。簡略化するとこんな感じ。

var hoge = {
  param: $('#hoge').val() // これが最初はundefined、2回目は値が入る
}

$.ajax({
  url: 'http://example.com',
  data: hoge
});

// http://example.com←最初の1回
// http://example.com?param=hoge←2回目以降だったのがタイムスタンプを付けたら
// http://example.com?param=undefined&timeStamp=123456←こうなってエラーになる

iOS6対応であんまり工数をかけるのも何なので、上記の対応の$.ajaxPrefilter()の後に $.ajax()のラッパー内で引数のoptionsを

for (var i in options.data) {
  if (options.data.hasOwnProperty(i)) {
    if (options.data[i] === undefined) {
      delete options.data[i];
    }
  }
}

として、無理矢理に消してしまうという処理を入れました。強引に過ぎる気もするけども、諸々事情があったので…。 というかObject.keys()使ってforループ回せば良かったんじゃないのか、これっていうのに今気付いた。