503を返すとか返さないとか言う前に。
公開日 : 2007-05-03 01:24:02
ここら辺に呼応して。
Googleのクローラーがどうかは調べていないけれど。
負荷云々の前に、まずきちんとHTTP_HEADERで攻防をしてから。
ステータスコードとその意味
200 | OK | リクエストは正常に処理された! |
301 | Moved Permanently | ページは移動したよ! |
302 | Found | 今のところページは移動してるよ! |
304 | Not Modified | リクエストされたページは更新されてないからキャッシュを使いな! |
401 | Unauthorized | 認証されてない! |
402 | Payment Required | 金払え! |
403 | Forbidden | 許可されないもんね! |
404 | File Not Found | ごめん, 見つかんないよ! |
500 | Internal Server Error | ごめん,俺が下手なせいで(Joke!)エラーなっちまったよ! |
503 | Service Unavailable | ごめん,今はだめだ! |
主立ったところはこんな感じ。
例えば(多分あまり意識していないであろう)Basic認証におけるHTTP_HEADERのやりとりは、
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="パスワード入れてね!"
(CRLF+CRLF)
というレスポンスをサーバが返し、クライアントは(ID,Passwdを求めるウィンドウを出してから)再度リクエストを送り返す。
GET /basic_auth.html HTTP/1.1
Authorization: Basic (base64エンコードされたID,Passwd情報)...
つまり、これもHTTP_Headerのやりとりなのだ。もちろんCookieだってそうだ。
このしくみを理解していればBasic認証を自前で実装することもできる。ID,PasswordをDBと照合してアクセスを許可することも可能。但し、Apache+Perl CGIの環境ではこの部分のHEADER情報が(おそらく)セキュリティの面(だったと思う)で環境変数から受け取ることができない(少なくとも昔はできなかった)ので無理。PHPであれば
$_SERVER['PHP_AUTH_USER']
$_SERVER['PHP_AUTH_PW']
とかで何でもできる。善し悪しは置いておいて。
また、バーチャルホストだって普通に使っているかもしれないが、
Host: junnama.alfasado.net
ってなヘッダー情報を送ってくるからApacheが適切に解釈できるわけで、ブラウザがHostヘッダを送ってこなければApacheはデフォルトサイトのデータを返すのだ(大昔はブラウザはこんな情報送ってこなかったからバーチャルホストってのもなかった)。
本題? に戻る。負荷軽減のポイントは
- HEADリクエストへの対応
- ステータス304を適切に返す
の2点か。
まともな? ロボットならまずは※HEADリクエストを送ってHTTP_HEADERをチェックするだろう。
※追記:
良く考えたら後述のConditionalGETが適切に機能するならばHEADリクエストである必要はないなぁ。
HEAD /index.html HTTP/1.1
If-Modified-Since: Mar, 3 Thu 2007 01:00:00 GMT
if_none_match: 23ab7f6be333b3df07b4df3de61a92b9
ページが更新されていないならば、HTTP_HEAD情報のみを返せば良い。
まともな? クローラーならこれで次のリクエストは送ってこない(と思う)。
HTTP/1.1 200 OK
Last-Modified: Mar, 3 Thu 2007 01:00:00 GMT
Content-type: text/html
Content-length: 950
Etag: 23ab7f6be333b3df07b4df3de61a92b9
あるいは(後述するが)
HTTP/1.1 304 Not Modified
Last-Modified: Mar, 3 Thu 2007 01:00:00 GMT
Content-type: text/html
Content-length: 950
Etag: 23ab7f6be333b3df07b4df3de61a92b9
さて、HEADリクエストで求める答えが得られなかったクライアントはConditional GET(条件付きGET)でリクエストを送ってくる(と考える)。
GET /index.html HTTP/1.1
If-Modified-Since: Mar, 3 Thu 2007 01:00:00 GMT
if_none_match: 23ab7f6be333b3df07b4df3de61a92b9
サーバー側の処理は
If-Modified-Since ヘッダで送られて来たタイムスタンプよりも送り返すべきデータの更新日時が新しい場合、あるいは以前送り返したEtagと値が変わっていた場合のみ
HTTP/1.1 200 OK
...HTTP_HEAD情報+CRLF+CRLF+コンテンツの内容
を送り返せば良い。
もしも更新されていなかったなら、ステータス304+返すべきHTTP_HEADER情報のみを送り返せば良い。そうすれば(それがブラウザであるならば)ブラウザのキャッシュが表示される。
HTTP/1.1 304 Not Modified
Last-Modified: Mar, 3 Thu 2007 01:00:00 GMT
Content-type: text/html
Content-length: 950
Etag: 23ab7f6be333b3df07b4df3de61a92b9
まともなクローラーであればこういう振る舞いをすべきだと思う(繰り返すがGoogleのクローラーがどうかは調べていないけれど)。
少なくとも503を返す前にやるべきことをやってから考えるべきではないだろうか?