mod_rewrite を使うときには 404 の扱いに注意
Posted by yoosee on Web at 2007-04-03 22:00 JST1 404 Blog Not Found:誤った404エラーページをつくるただ1つの方法
言ってることはもっともなんだけど、例を見たときには何を問題視しているか分からなかった。誤った404エラーページをつくるただ1つの方法、それはStatus 404を返さないことなのです。と言うのも、例示が % HEAD -S http://caramel-tea.com/404.php となっていたから。存在するコンテンツなのだから 200 が返るのは当然だ。と言うことで実際には存在しない http://caramel-tea.com/foo/bar/aa へアクセスしてみると
ところが、未だにエラーなのにStatus 200を返すURIがあふれています。404 Blog Not Found:誤った404エラーページをつくるただ1つの方法
% HEAD -S http://caramel-tea.com/foo/bar/aa HTTP/1.1 200 OK Date: Tue, 03 Apr 2007 23:14:22 GMT Server: Apache Cache-Control: no-cache, must-revalidate, max-age=0 Expires: Wed, 11 Jan 1984 05:00:00 GMT Pragma: no-cache X-Pingback: http://caramel-tea.com/xmlrpc.php Status: 404 Last-Modified: Tue, 03 Apr 2007 23:14:28 GMT Connection: close Transfer-Encoding: chunked Content-Type: text/html; charset=UTF-8おお、こちらも確かに 200 が返ってる。これはよろしくない。ちなみに netcraft で調べても OS と Webサーバが不明だが、ホストは xrea.com のものらしいので スペック を見る限りは Linux / Apache らしい。
ご存知だろうが Apache ならば設定ファイルや .htaccess に
ErrorDocument 404 /404.htmlと書けば、static な URI のコンテンツを Status Code 404 で表示させることが出来る。例にそう設定してアクセスしてみると
% HEAD -S http://yoosee.net/foo HTTP/1.1 404 Not Found Date: Tue, 03 Apr 2007 23:00:31 GMT Server: Apache/1.3.37 (Unix) Last-Modified: Tue, 03 Apr 2007 22:59:06 GMT ETag: "33921c-76-46142dba;46142de6" Accept-Ranges: bytes Content-Length: 118 Content-Type: text/htmlHTTP コードとして 404 が返っており、問題ない。ちなみに ErrorContent に http:// で始まる URI を入れた場合には 302 で他所に飛ばされるようだ。
HTTP/1.1 302 Found Date: Tue, 03 Apr 2007 01:42:52 GMT Server: Apache/1.3.37 (Unix) Location: http://yoosee.net/404.html Connection: close Content-Type: text/html; charset=iso-8859-1これはこれでよろしくないが、caramel-tea.com の例とはまた違う。予測できるのは、恐らく caramel-tea.com では mod_rewrite で存在しないページを別ページに飛ばしているのだろう。
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ /404.php [L]こんな感じでファイルやディレクトリの存在確認演算子 -f や -d を使えば、存在しなかった場合の RewriteRule を書くことが出来る。手元で試したものは ErrorDocument 404 が指定されていても 200 が返されたので、恐らくこれが原因ではなかろうか。
ちなみに呼び出し先を cgi にして
#!/usr/bin/env ruby require 'cgi' cgi = CGI.new puts cgi.header("type" => "text/html", "status" => "NOT_FOUND") puts "<html><body>404 not found.</body></html>"のように CGI 側で明示的に 404 を返した場合には、Rewrite 経由でもきちんと 404 が返った。php でのやり方は知らないが、同様にステータスコードは返せるのではないかと思う。
ちなみに Google への対処策としてはGoogle ウェブマスター向けヘルプセンター - 存在しないページに対してサーバーから 200 (見つかりました) ステータスが返されました にあるように meta タグで回避することも出来るが、他のロボットも考えればきちんと HTTP のレスポンスコードで 404 を返すべきだ。そうしておけば、ログ解析時に 404 が発生している事を確認するといった作業が容易く行えると言うメリットもある。