Android 2.3 の WebView のクロスドメインリクエスト(続編)
ここ数ヶ月かなり忙しく更新をサボっていたので疑問に思っていたことを。
モバイルのサイトをやっているとどうしても避けられないのが古いデバイスへの対応。 悩ましいのがAndroid2.3のようなデバイス達*1。例え中古で二束三文で売られていたしてもは出来の悪いかわいい子などとは到底思えない。
CSSや操作に関する問題は別のサイト*2に譲るとして、血の気が引きそうな
の記事に関して自分でもう一度調べて(勝手に)続編を書いてみた。
結果: 再現 (但し条件あり)
「最初の1回だけ」というのがポイントのよう。つまりキャッシュに起因した問題。
前述のブログの検証の通りjQueryでテストコードを書いて検証した。
ここでいうキャッシュとは、$.ajax({ cache: true
のこと。
2回目のクロスドメインリクエスト処理結果
NGの場合はstatus=0
が返ってくる。
OS Version | Browser | Cache | JSONP | GET | POST | DELETE |
---|---|---|---|---|---|---|
Android2.3.4 | 標準ブラウザ | 有効 | OK | NG | OK | NG |
無効 | OK | OK | OK | NG | ||
WebView | 有効 | OK | NG | OK | NG | |
無効 | OK | OK | OK | NG | ||
Android2.3.5 | 標準ブラウザ | 有効 | OK | NG | OK | NG |
無効 | OK | OK | OK | NG | ||
WebView | 有効 | OK | NG | OK | NG | |
無効 | OK | OK | OK | NG |
Android4.0.4 と Android4.4.2では全てOK。iOSでも問題なし。特にWebViewと標準ブラウザでの挙動の違いは見られない。 JSONPとPOSTを使っていれば問題無しという結果に。
DELETEがキャッシュを無効にしても失敗?
次の疑問はDELETEの列。ヒントになったのはキャッシュ無しをどう実現しているかだった。
XMLHttpRequestのキャッシュ
var req = new XMLHttpRequest(); req.open ('GET', 'test.txt', true); req.setRequestHeader('Pragma', 'no-cache'); // HTTP/1.0 における汎用のヘッダフィールド req.setRequestHeader('Cache-Control', 'no-cache'); // HTTP/1.1 におけるキャッシュ制御のヘッダフィールド req.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT'); // 指定日時以降に更新があれば内容を返し、更新がなければ304ステータスを返すヘッダフィールド。古い日時を指定すれば、必ず内容を返す
のように設定すればよいと思われる。実際クロスドメインでこれらのヘッダを設定するにはおそらく Access-Control-Allow-Headers
などサーバ側の対応も必要(今回は試せていない)。
jQueryのajaxのキャッシュ
jQueryのキャッシュはこのXMLHttpRequestのものとは別でソース(http://code.jquery.com/jquery.js)を見てみると
// Add anti-cache in url if needed if ( s.cache === false ) { // 省略 // Otherwise add one to the end cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++; }
こんな感じでURLに意味のない文字列_=1445733432387
を付与していることで一意にすることでキャッシュ無しを実現している。
が、POSTやDELETEにcacheオプションを設定してもエラーにならないが、POSTやDELETEのときに飛んでいるリクエストを見ると付与されないことがわかる。
POSTは元々平気なのでDELETEのときだけキャッシュの問題を踏んでしまい、先ほどのように動作しない結果となる。
実際にDELETEのリクエストURLに'&_='+Math.floor($.now()/1000))
を付与したところ正しく動作した。
まとめ
ひとまず自分が行った検証結果では
- 標準ブラウザとWebViewの違いは見られない
- JSONPやPOSTは問題無し
- GETやDELETEはキャッシュのコントロールに気をつければ2回目の通信は可能
となった*3。
*1:Android2.3のシェアはDashboards | Android Developersによると3.8%
*2:to-R AndroidやiPhoneのHTML,CSS,JavaScriptのバグまとめ http://blog.webcreativepark.net/2012/03/13-093853.htmlは特に役立つ
*3:よく考えるとサーバ側はPOST/DELETEは更新なのでレスポンスをno-cacheで返すのが正しいやり方なのだろうか