Ajax File Uploadのバグとその対策

/ Text by

Pickls作ってて気がついたんだが、SafariでAjaxファイルアップロードを行うと、ファイルの送信処理に入ったままそこでJavaScriptの実行が完全にフリーズすることがある。JavaScriptエラーになるわけでもなく、ただフリーズをする。

Ajaxでファイルアップロード処理を行うような場合、処理中であることを示すためにプログレスバーを表示したりスピナーを表示したりすることが多いと思いますが、つまりこのバグに当たるとユーザーは永遠にスピナーの回転を見続けることになる。何らかのファイルをアップロードすることで成立するサービスにとっては致命的。

初めは自分のコードを疑ったもののどう考えても間違いはないと判断してバグなのでは… と調べてみたところ、どうやらSafari 4の時点でも同様の現象がありそれがSafari 5になっても修復されていないという報告がDrupalのフォーラムに上がっていた。さらに自分では確認できなかったものの同じ現象がChromeやOperaでも発生するとのこと。

根本的な原因は定かでないもののどうやらバグを引き起こしているのは HttpConnection で、これが Keep-Alive になっているとけっこうな頻度でファイルアップロードでこける。

これを回避するには以下のような非同期のAjax通信を行う関数を用意してファイルアップロードの直前に実行するといいらしい。

/* jQuery使用の場合 */

function closeKeepAlive() {
    if (/AppleWebKit|MSIE/.test(navigator.userAgent)) {
        $.ajax({ url: "/ping/close", async: false });
    }
}

“/ping/close” にファイルやディレクトリが存在している必要はなく(むしろ存在していない方がいい)、通信に失敗した時点で HttpConnection がいったん close となり、本来の目的とするファイルアップロード実行の際には再び開いてうまく実行されるという仕掛けのようです。

ほんまかいな。。と思いましたが確かにこれで直った。

ちなみにPHPを利用しているならページ読み込み時にはじめから

header("connection: close");

としてHTTPヘッダを送信しておけばいいっぽい。