クエリ文字列(URLパラメタ)があるURLでのmod_rewriteの使い方
mod_rewriteを使用してクエリ文字列(URLパラメタ)があるURLを変換してリダイレクトしようとしたときに少しハマリかけたので、備忘録として書いておきます。
今回リダイレクトしたURL
今回は、以下の旧URLから新URLにリダイレクトさせるケースでやってみました。
内容としては、旧URLのクエリ文字列(URLパラメタ)の「id」「name」に設定された値が、新URLではディレクトリとファイル名として使用できるようにするといったものです。
旧URL | 新URL | |
---|---|---|
形式 | /foo/index.html?id=数字列&name=文字列 | /foo/文字列/数字列.html |
サンプル | /foo/index.html?id=123&name=bar | /foo/bar/123.html |
RewriteRuleで試す
まずは「RewriteRule」で正規表現を使ってリダイレクトする設定を書いてみました。
URLの書き換えは正規表現で行ないます。
「恒久的なサイトの移転」とするために「R=301」を指定してます。
RewriteEngine On RewriteRule ^foo/index.html\?id=(\d{3})&name=([a-z]+)$ /foo/$2/$1.html? [R=301,L]
上記の設定をした上で、ページにアクセスしてみます。
ページへのアクセスは普通にブラウザからでも可能ですが、今回は「telnet」でアクセスしてみます。
「telnet」でアクセスはコマンドライン上で実行出来るのと、HTTPステータスコード等が明確に確認できるのでなかなか便利です。
$ telnet localhost 80 Trying ::1... Connected to localhost. Escape character is '^]'. GET /foo/index.html?id=123&name=bar HTTP/1.0 User-Agent: Telnet [ja] (Linux) Host: localhost HTTP/1.1 404 Not Found Date: Thu, 21 Oct 2010 23:31:15 GMT Server: Apache Accept-Ranges: bytes Connection: close Content-Type: text/html; charset=none
「GET /foo/index.html?id=123&name=bar」でアクセスしましたが、リダイレクトされずに404で戻ってきてしまっています。
RedirectMatchで試す
次にRewriteRule(mod_rewrite)ではなく、RedirectMatchを使ってみました。
正規表現の書き方とかはほとんど同じです。
「恒久的なサイトの移転」とするために「permanent」を指定してます。これは「301」と指定しても同じ意味になります。
RedirectMatch permanent ^/foo/index.html?id=(\d{3})&name=([a-z]+)$ /foo/$2/$1.html
先程と同じようにtelnetでhttpアクセスをしてみます。
$ telnet localhost 80 Trying ::1... Connected to localhost. Escape character is '^]'. GET /foo/index.html?id=123&name=bar HTTP/1.0 User-Agent: Telnet [ja] (Linux) Host: localhost HTTP/1.1 404 Not Found Date: Thu, 21 Oct 2010 23:34:53 GMT Server: Apache Accept-Ranges: bytes Connection: close Content-Type: text/html; charset=none
状況は変わらず、リダイレクトされずに404で戻ってきてしまっています。
RewriteRuleはクエリ文字列(URLパラメタ)を含んでいない
手元にあった「Apacheクックブック第2版」で調べてみるとこのような記述がありました。
mod_rewriteのマッチングと書き換え処理では、クエリ文字列(URLパラメタ)をURIの一部として見なさないため、別々に扱う必要がある。
Apacheクックブック第2版 p94より抜粋
%{QUERY_STRING}を参照する必要がある。
RewriteRuleではクエリ文字列(URLパラメタ)無しのURIしか見ない。
つまりは、「RewriteRule」で書き換えられる側のURIには「クエリ文字列(URLパラメタ)が含まれない」ため、上記の方法では正規表現がマッチせずにそのまま「/foo/index.html」を表示してしまっていたようです。
※「RedirectMatch」についての記述はありませんでしたが、WEBで調べてみると同様の問題のようでした。
RewriteCondとRewriteRuleを使う
ということで、「RewriteRule」以外に「RewriteCond」でクエリ文字列(URLパラメタ)を抽出する条件を追加してみます。
クエリ文字列(URLパラメタ)は「%{QUERY_STRING}」に格納されています。
今回の例の場合だと「%{QUERY_STRING}」には「id=123&name=bar」という文字列がセットされていることになります。
これを踏まえた上で設定してみます。
Options +FollowSymLinks RewriteEngine On RewriteCond %{QUERY_STRING} id=([0-9]{3})&name=([a-z]+)$ RewriteRule ^foo/index.html$ /foo/%2/%1.html? [R=301,L]
またまた同じようにtelnetでhttpアクセスをしてみます。
$ telnet localhost 80 Trying ::1... Connected to localhost. Escape character is '^]'. GET /foo/index.html?id=123&name=bar HTTP/1.0 User-Agent: Telnet [ja] (Linux) Host: localhost HTTP/1.1 301 Moved Permanently Date: Thu, 21 Oct 2010 23:36:44 GMT Server: Apache Location: http://localhost/foo/bar/123.html Content-Length: 246 Connection: close Content-Type: text/html; charset=iso-8859-1
HTTPヘッダ部分の「HTTP/1.1 301 Moved Permanently」と「Location: http://localhost/foo/bar/123.html」から、今度はhttp://localhost/foo/bar/123.htmlへリダイレクトされていることが確認できました。
ブラウザからアクセスしても正常にアクセスすることができました。
ちょっとハマリかけましたが、mod_rewriteっておもしろいです。
今回参考にしたページ
Apache module mod_rewrite
http://japache.infoscience.co.jp/japanese_1_3_6/manual/mod/mod_rewrite.html
URIのリダイレクト設定をやってみた(管理人日記) - むぅもぉ.jp
http://muumoo.jp/news/2006/04/06/0redirect.html
クエリー付のリダイレクトは「mod_rewrite」を使うべし Project MultiBurst
http://www.multiburst.net/project-multiburst/archives/2007/01/07/1923.php
telnetでブラウズ(HTTP)
http://ash.jp/net/telnet_http.htm