Kanasan.JS JavaScript第5版読書会#9 に参加した

2010/2/14(土) Kanasan.JS JavaScript第5版読書会#9 に参加した(告知ページ)。

今回読んだところは P479 から P528まで。特に後半は XMLHttpRequest に関する章で、色々ふむふむしながら読んだ。以下、分かったことのメモ。

open メソッドの第4、第5引数

XMLHttpRequest の open メソッドには省略可能な第4、第5引数がある。それぞれ Basic 認証の「ユーザ名」「パスワード」として使用できるらしい。

というわけで、さっそく試してみた。

Basic 認証のかかったサンプルページがあったので、そこに xhr でリクエストを投げて、Wireshark で通信の内容を見てみた。

まず、JavaScript のコードはこんな感じ。サンプルページを開いて firebug のコンソールに貼り付けて実行した。

var url =  "http://websoft.niikest.com/scripts/wpba/sample/sample1.html"
var username = "guest";
var password = "testpwd1";
var xhr = new XMLHttpRequest();
xhr.open("GET", url, false, username, password);
xhr.send(null);

で、送受信した HTTP のヘッダはこんな感じ。一部関係ない行は省略した。

まず最初のリクエスト。

GET /scripts/wpba/sample/sample1.html HTTP/1.1
Host: websoft.niikest.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.9.2) Gecko/20100115 Firefox/3.6
Referer: http://websoft.niikest.com/scripts/wpba/sample.html

普通に GET してる。

で、サーバからのレスポンスが返ってくる。

HTTP/1.1 401 Authorization Required
WWW-Authenticate: Basic realm="IDpX[hF"
Content-Type: text/html; charset=iso-8859-1

「どこの誰だか分かんないやつには教えてやんねーぜ!」ってわけで、401 認証エラー。

んで、ブラウザから再度リクエストを投げる。

GET /scripts/wpba/sample/sample1.html HTTP/1.1
Host: websoft.niikest.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.9.2) Gecko/20100115 Firefox/3.6
Referer: http://websoft.niikest.com/scripts/wpba/sample.html
Authorization: Basic Z3Vlc3Q6dGVzdHB3ZDE=

「待ってくれよ! 俺だよ、俺!」ってことで、あわてて最後に Authorization ヘッダを付加してる。

これで認証通るか?

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1230

やったぜ、200 OK! というわけでめでたく認証が通りました。

まとめとしては、一回普通にリクエスト投げて、認証エラーの場合は Authorization ヘッダにユーザ名とパスワードを付けて再送信する。

ちなみに、Basic 認証がかかったページにユーザ名とパスワードなしで(つまり第4、第5引数を省略して)リクエストを投げると、普通にブラウザで認証ページを開いた時みたいにパスワード入力を促すダイアログが出る。

getResponseHeader メソッド

getResponseHeader メソッドを使うと、指定した名前のレスポンスヘッダ行が取得できる。

if (xhr.getResponseHeader("Content-Type") === "text/xml") {
    // XML の場合の処理
}

「getAllResponseHeaders で全ヘッダを取得して、split("\n")で分割して、」みたいなことをやらなくても OK。

リクエストのタイムアウト処理

ちゃんとやるなら、サーバ側が応答を返さない場合のタイムアウト処理も入れておいた方がいい。

こんな感じでリクエストを送信する前にタイムアウト処理を仕掛けておく。

var timer = setTimeout(
    function() {
        xhr.abort();
        // 適当にタイムアウトの場合のエラー処理
    },
    20 * 1000 // 20秒でタイムアウトする
);
// ちゃんと受信できた場合にはタイマーをキャンセルする
xhr.onreadystatechange = function() {
    if (xhr.redayState === 4) {
        clearTimeout(timer);
        // 成功の場合の処理
    }
};

jQuery でもタイムアウトをサポートしてる。使い方はこんな感じ。

$.ajax({
    type: "GET",
    url: "test.html",
    success: function(html) {
        // 成功の場合の処理
    },
    timeout: 20 * 1000, // 20秒でタイムアウトする
    error: function(xhr, status, errorThrown) {
        if (status === "timeout") {
            // タイムアウトの場合のエラー処理
        }
    }
});

うむ、便利。

まとめ

まず思ったことは、 XMLHttpRequestAPI って使いにくい。open と send 二つあるのは分かりにくいし、onreadystatechange ハンドラに引数が渡されないってのも不便だ。

実はこういうのって jQuery とかライブラリ使うことが多いので、中身の詳しいこと知らなくても書けるんだよね。でもやっぱりその中で何やってるか気になるし、どういうことができるのか分かって良かった。

今回は会場の都合もあって時間は短めだったけど、中身の濃い勉強会でした。