mod_rewriteのコンテキストとサブリクエストについて調べた。こせきの技術日記スマートフォン用の表示で見るこせきの技術日記この広告は、90日以上更新していないブログに表示しています。2009-09-21mod_rewriteのコンテキストとサブリクエストについて調べた。Apache発端WordPressでパーマリンクをカスタマイズすると、下の設定を.htaccessに書くように言われる。[L]これをhttpd.confに移すと以下のように書ける(と思っていた)。[L]DirectoryIndexにindex.phpを足す。index.htmlこの設定で.htaccessとhttpd.confで動作が微妙に違うことに気づく。以下、httpd.confを(S).htaccessを(D)と表記する。(S)はサーバコンテキスト、(D)はディレクトリコンテキスト。/index.phpを表示する。/index.phpを表示する。/index.phpを表示する。Forbiddenになる。/index.phpを表示する。/xxx/index.htmlを表示する。/xxx/index.phpを表示する。/xxx/index.phpを表示する。この違いが全く理解できなかった。httpd.confに設定すると、DirectoryIndexの2番目以降のエントリ(index.html)が無視されてしまうのが困った。RewriteLogでもピンとこなかったので、mod_dirにパッチをあてて調べた。前提mod_rewriteの基本については以下の記事を参照。mod_rewriteの考え方。Rewritesに解説がある。<Directory>にRewriteRuleを書くのは避けるべき。プレフィックス置換(RewriteBase)が複雑なので。<Location>にRewriteRuleを書く理由はない。書けるがサポートしない。contextはバーチャルホスト設定を含む。モジュールの実行順序について以下の記事を頼りにソースを読んだ。目次がたぶんだいたい呼び出し順。最初の方のフックで、サーバコンテキストのRewriteRule適用。(間に長い道のりを経て)最後の方のフックで、ディレクトリコンテキストのRewriteRuleとDirectoryIndex適用。DirectoryIndexはindex.phpやindex.htmlを探すためにサブリクエストを発行し、サブリクエストにも各モジュールが適用される。最初に書いた動作の違いはどこからくるのか。mod_dirが発行したサブリクエストをRewriteRuleが書き換えたとき(図の赤矢印)、サーバコンテキストなら受け入れる。ディレクトリコンテキストなら捨てる。/index.phpを表示する。/index.phpを表示する。(S)(D)ともメインリクエストでリライトが完了する。!-fにも!-dにもマッチするため。サブリクエストは発行されない。/index.phpを表示する。/index.php)この結果を受け入れる。DirectoryIndexの残りのエントリーは無視される。Forbiddenになる。/index.php)mod_dirが結果を破棄/xxx/にそのままアクセス。/index.phpを表示する。/xxx/index.phpから/index.phpにリライトされる。DirectoryIndex無視。/xxx/index.htmlを表示する。/index.php)mod_dirが結果を破棄mod_dirがサブリクエスト(/xxx/index.html)ファイルがあるので、RewriteRuleは適用されない。/xxx/index.htmlを表示。/xxx/index.phpを表示する。/xxx/index.phpを表示する。(S)(D)ともmod_dirの最初のサブリクエスト(ファイルがあるのでRewriteRuleは適用されない)の結果を受け入れて/xxx/index.phpが表示される。サーバコンテキストで%{DOCUMENT_ROOT}を指定することの問題mod_aliasはサーバコンテキストのリライトより後に実行される。APR_HOOK_MIDDLEサーバコンテキストの時点で、mod_rewriteはパスが何になるかわからない。URIは知っているがパスを知らない。パスは知っているがURIを知らない。ディレクトリコンテキストでは、書き換え後にサブリクエストを発行するため、RewriteBaseを使ってパスをURIに戻す必要がある。サーバコンテキストでパスを知るには、サブリクエストを発行しなければならない。%{LA-F:variable}というのがその値。LA-FはLA-Uとほぼ同義でサブリクエストを発行して最終的な値を得る。ファイルのパスを知りたいときはLA-UではなくLA-Fを使う。Server%{LA-F:REQUEST_FILENAME}を実行するとサブリクエストが発行され、サブリクエストにはmod_rewriteが適用される。再帰がループしそうだが、ループ回避のためsubreq_okというマクロが使われている。サブリクエストではない場合、またはメインリクエストとサブリクエストのURIが一致しない場合のみ処理が許可される。r->uri)))また、サブリクエストの回数と再帰レベルはLimitInternalRecursionで設定できる。デフォルトは回数・深さ共に10。LimitInternalRecursionディレクティブともあれサブリクエストを発生させてまで厳密なパスを知りたいわけではない。DOCUMENT_ROOTでもたいていは事足りるのではないか。Aliasを足したらAlias用のリライト設定も足せばいい。ディレクトリコンテキストでもAliasディレクトリ以下でリライトするなら、そこに.htaccessを足すなり<Directory>を足すなりしなければならない。サーバコンテキスト編サーバコンテキストに設定した場合に困るのが、/xxx/index.htmlが表示できなくなるところ。DirectoryIndexの2番目以降の項目が無視されてしまう。そこで、DirectoryIndexをRewriteRuleで置き換える。リクエストがディレクトリでindex.phpがあれば内部リダイレクトして終了。リクエストがディレクトリでindex.htmlがあれば内部リダイレクトして終了。[L]ただし、これでも空のディレクトリ/xxx/にアクセスするとサブリクエストが発生してしまう。DirectoryIndex設定を外しても、デフォルトのindex.htmlが設定されてしまって効果が無い。意地でもサブリクエストを出さない設定。ディレクトリがあって、インデックスがない場合にForbidden。2.1.1以上なら404も返せる。[R=404]インデックス無しディレクトリに大量にアクセスがあるなら別だが、普通はメリット無さそう。Forbiddenの代わりに404を返したい時は使うかもしれない。mod_dirを外してしまうのはどうだろう?mod_dirを外せば、上の設定は不要になる。mod_dirのもう一つの機能、DirectorySlashもRewriteRuleで代用できる。[L,R=301,NE]これもやり過ぎか。上で書いたとおり、Aliasで指定したディレクトリはDOCUMENT_ROOTにマッチしないので注意。Aliasへのアクセスを%{DOCUMENT_ROOT}用のルールから除外する。この下にDOCUMENT_ROOT用のRewriteRuleのようにする。Alias以下をリライトしない場合でも、DOCUMENT_ROOT以下のファイルを見に行ってしまわないように、最後のストッパーは書いた方がいい。ディレクトリコンテキスト編ディレクトリコンテキストは効率が悪いが、動作はほぼ問題ない。可能なら.htaccessではなく<Directory>に書くこと。サーバコンテキストと同様、DirectoryIndexをRewriteRuleで代用して、サブリクエストを回避できる。!-dを外す選択肢もある。ami-e048af89)EC2でami-e048af89を起動、rootで000-start.shを実行すると、Apacheをビルドしログ出力用のパッチをあてたmod_dirが動くテスト環境をセットアップする。logでログをみながらhttp://localhost/xxx/にアクセス。directory_confでサーバコンテキスト・ディレクトリコンテキストの切り替えを行う。00:00mod_rewriteのコンテキストとサブリクエストについて調べた。生のデータが見たい...2012-02-12HTTPのクエリパラメータにコロン(:)を書くのは不正なのか。$_SERVER['REQUEST...2009-07-21WordPressをアプリケーションフレームワークとして使う。WordPressを使ってアプリケーションを開発した。これまでWordPr...2009-06-11mod_rewriteの考え方。要素とブロックを渡すの、どっちが速いの?月別アーカイブはてなブログをはじめよう!koseki2さんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。