最近、かなりの数のmod_rewrite
スレッドが浮かんでいるようですが、その特定の側面がどのように機能するかについて少し混乱しています。その結果、私は一般的な機能に関するいくつかのメモと、おそらくいくつかの厄介なニュアンスをまとめました。
他にどのような機能/一般的な問題を使用して遭遇しましたmod_rewrite
か?
最近、かなりの数のmod_rewrite
スレッドが浮かんでいるようですが、その特定の側面がどのように機能するかについて少し混乱しています。その結果、私は一般的な機能に関するいくつかのメモと、おそらくいくつかの厄介なニュアンスをまとめました。
他にどのような機能/一般的な問題を使用して遭遇しましたmod_rewrite
か?
mod_rewrite
ルールは、httpd.conf
ファイル内またはファイル内に配置.htaccess
できます。にアクセスできる場合は、ここにルールを配置すると、パフォーマンスが向上します(ファイルが呼び出されるhttpd.conf
たびにルールが処理されるのではなく、ルールが1回処理されるため)。.htaccess
ロギングはファイル内から有効にできhttpd.conf
ます(を含む<Virtual Host>
):
# logs can't be enabled from .htaccess
# loglevel > 2 is really spammy!
RewriteLog /path/to/rewrite.log
RewriteLogLevel 2
すべてのリクエストを1つのポイントに集めるには:
RewriteEngine on
# ignore existing files
RewriteCond %{REQUEST_FILENAME} !-f
# ignore existing directories
RewriteCond %{REQUEST_FILENAME} !-d
# map requests to index.php and append as a query string
RewriteRule ^(.*)$ index.php?query=$1
Apache 2.2.16以降、を使用することもできますFallbackResource
。
301/302リダイレクトの処理:
RewriteEngine on
# 302 Temporary Redirect (302 is the default, but can be specified for clarity)
RewriteRule ^oldpage\.html$ /newpage.html [R=302]
# 301 Permanent Redirect
RewriteRule ^oldpage2\.html$ /newpage.html [R=301]
注:外部リダイレクトは暗黙的に302リダイレクトです。
# this rule:
RewriteRule ^somepage\.html$ http://google.com
# is equivalent to:
RewriteRule ^somepage\.html$ http://google.com [R]
# and:
RewriteRule ^somepage\.html$ http://google.com [R=302]
SSLを強制する
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/$1 [R,L]
一般的なフラグ:
[R]
または[redirect]
-リダイレクトを強制します(デフォルトは302一時リダイレクト)[R=301]
または[redirect=301]
-301の永続的なリダイレクトを強制します[L]
または[last]
-書き換えプロセスを停止します(一般的な落とし穴については、以下の注を参照してください)[NC]
または[nocase]
-マッチングで大文字と小文字を区別しないように指定します
多くの場合、長い形式のフラグを使用すると読みやすくなり、後でコードを読むようになる他の人に役立ちます。
複数のフラグをコンマで区切ることができます。
RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
混合mod_alias
スタイルのリダイレクトmod_rewrite
# Bad
Redirect 302 /somepage.html http://example.com/otherpage.html
RewriteEngine on
RewriteRule ^(.*)$ index.php?query=$1
# Good (use mod_rewrite for both)
RewriteEngine on
# 302 redirect and stop processing
RewriteRule ^somepage.html$ /otherpage.html [R=302,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# handle other redirects
RewriteRule ^(.*)$ index.php?query=$1
注mod_alias
:と組み合わせることができますがmod_rewrite
、上記のように基本的なリダイレクトを処理するだけではなく、より多くの作業が必要になります。
コンテキストは構文に影響します
ファイル内.htaccess
では、先頭のスラッシュはRewriteRuleパターンでは使用されません。
# given: GET /directory/file.html
# .htaccess
# result: /newdirectory/file.html
RewriteRule ^directory(.*)$ /newdirectory$1
# .htaccess
# result: no match!
RewriteRule ^/directory(.*)$ /newdirectory$1
# httpd.conf
# result: /newdirectory/file.html
RewriteRule ^/directory(.*)$ /newdirectory$1
# Putting a "?" after the slash will allow it to work in both contexts:
RewriteRule ^/?directory(.*)$ /newdirectory$1
[L]は最後ではありません!(時折)
フラグは、ルールセットを通過するそのパスの[L]
それ以上の書き換えルールの処理を停止します。ただし、そのパスでURLが変更され、コンテキストまたはセクションにいる場合、変更されたリクエストはURL解析エンジンを介して再度渡されます。そして次のパスでは、今回は別のルールに一致する可能性があります。これを理解していない場合は、フラグが効果がなかったように見えることがよくあります。.htaccess
<Directory>
[L]
# processing does not stop here
RewriteRule ^dirA$ /dirB [L]
# /dirC will be the final result
RewriteRule ^dirB$ /dirC
書き換えログには、ルールが2回実行され、URLが2回更新されていることが示されています。
rewrite 'dirA' -> '/dirB'
internal redirect with /dirB [INTERNAL REDIRECT]
rewrite 'dirB' -> '/dirC'
これを回避する最善の方法は、ルール(および後続のパス)のそれ以降のすべての処理を本当に停止したい場合は、フラグの代わりに[END]
フラグ(Apacheドキュメントを参照)を使用することです。[L]
ただし、フラグはApache v2.3.9以降[END]
でのみ使用できるため、v2.2以下を使用している場合は、フラグだけで問題が発生します。[L]
RewriteCond
以前のバージョンでは、URL解析エンジンの後続のパスでルールが一致しないように、ステートメントに依存する必要があります。
# Only process the following RewriteRule if on the first pass
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ...
または、RewriteRuleがhttpd.conf
、リクエストが再解析されないコンテキスト(つまり)にあることを確認する必要があります。
内部リダイレクト/書き換えが .htaccess で発生するのを「ブロック」する必要がある場合は、
RewriteCond %{ENV:REDIRECT_STATUS} ^$
ここで説明されているように、状態。
RewriteBase との契約:
ほとんどの場合、RewriteBase を設定する必要があります。そうしないと、apache はベースがディレクトリへの物理ディスク パスであると推測します。だから、これから始めます:
RewriteBase /
その他の落とし穴:
1- MultiViews を無効にすることをお勧めする場合があります
Options -MultiViews
私は MultiViews のすべての機能に精通しているわけではありませんが、アクティブなときに mod_rewrite ルールを台無しにすることは知っています。そのプロパティの 1 つは、探していると思われるファイルの拡張子を試して「推測」することだからです。 .
説明します: Web ディレクトリに file1.php と file2.php の 2 つの php ファイルがあり、これらの条件とルールを .htaccess に追加するとします。
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ file1.php/$1
ファイルまたはディレクトリに一致しないすべての URL が file1.php によって取得されると仮定します。サプライズ!このルールは、URL http://myhost/file2/somepathには適用されません。代わりに、file2.php の中に入ります。
何が起こっているかというと、MultiViews は、実際に必要な URL がhttp://myhost/file2.php/somepathであると自動的に推測し、喜んでそこに連れて行ったということです。
今、あなたは何が起こったのかわからず、その時点で、mod_rewrite について知っていると思っていたことすべてに疑問を抱いています。次に、この新しい状況の背後にあるロジックを理解するためにルールをいじり始めますが、テストすればするほど意味がなくなります。
わかりました。要するに、mod_rewrite をロジックに近い方法で動作させたい場合は、MultiViews をオフにすることが正しい方向への一歩です。
2-FollowSymlinks を有効にする
Options +FollowSymLinks
あれ、詳しくはよくわからないけど、何度も言ってるのを見たからやってみよう。
方程式は次の例で実行できます。
RewriteCond %{REQUEST_URI} ^/(server0|server1).*$ [NC]
# %1 is the string that was found above
# %1<>%{HTTP_COOKIE} concatenates first macht with mod_rewrite variable -> "test0<>foo=bar;"
#RewriteCond search for a (.*) in the second part -> \1 is a reference to (.*)
# <> is used as an string separator/indicator, can be replaced by any other character
RewriteCond %1<>%{HTTP_COOKIE} !^(.*)<>.*stickysession=\1.*$ [NC]
RewriteRule ^(.*)$ https://notmatch.domain.com/ [R=301,L]
動的負荷分散:
mod_proxyを使用してシステムのバランスをとる場合、ワーカーサーバーのダイナミックレンジを追加することができます。
RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC]
RewriteRule (.*) https://worker%1.internal.com/$1 [P,L]
[L] フラグの理解を深める必要があります。[L] フラグは最後です。リクエストが再度 URL 解析エンジンを経由する原因を理解する必要があります。ドキュメントから(http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_l)(私の強調):
[L] フラグにより、mod_rewrite はルール セットの処理を停止します。ほとんどの場合、これは、ルールが一致した場合、それ以上のルールは処理されないことを意味します。これは、Perl の最後のコマンド、または C の break コマンドに対応します。このフラグを使用して、それ以上のルールを考慮せずに現在のルールをすぐに適用する必要があることを示します。
.htaccess ファイルまたは
<Directory>
セクションで RewriteRule を使用している場合は、ルールがどのように処理されるかをある程度理解しておくことが重要です。これを簡略化すると、ルールが処理されると、書き換えられたリクエストがURL 解析エンジンに返され、可能な処理が行われます。書き換えられた要求が処理されると、.htaccess ファイルまたは<Directory>
セクションが再び検出され、ルールセットが最初から再実行される可能性があります。最も一般的なのは、ルールの 1 つがリダイレクト (内部または外部のいずれか) を引き起こし、リクエスト プロセスが最初からやり直された場合です。
したがって、[L] フラグは、ルール セットを通過するそのパスのそれ以上の書き換えルールの処理を停止します。ただし、[L] でマークされたルールがリクエストを変更し、.htaccess コンテキストまたは<Directory>
セクションにいる場合、変更されたリクエストは URL 解析エンジンを介して再度渡されます。そして次のパスでは、今回は別のルールに一致する可能性があります。何が起こったのかわからない場合は、[L] フラグを使用した最初の書き換えルールが効果がなかったようです。
これを回避する最善の方法は、本当に停止したい場合は、[L] フラグの代わりに[END] フラグ ( http://httpd.apache.org/docs/current/rewrite/flags.html#flag_end ) を使用することです。ルールの以降のすべての処理 (およびその後の再解析)。ただし、[END] フラグは Apache v2.3.9+ でのみ使用できるため、v2.2 以前を使用している場合は [L] フラグだけで立ち往生しています。この場合、RewriteCond ステートメントに依存して、URL 解析エンジンの後続のパスでルールが一致しないようにする必要があります。または、RewriteRule が、リクエストが再解析されないコンテキスト (つまり、httpd.conf) にあることを確認する必要があります。
もう 1 つの優れた機能は、rewrite-map-expansions です。これらは、処理するホスト/書き換えが大量にある場合に特に役立ちます。
それらはキー値の置換のようなものです:
RewriteMap examplemap txt:/path/to/file/map.txt
次に、ルールで次のようなマッピングを使用できます。
RewriteRule ^/ex/(.*) ${examplemap:$1}
このトピックの詳細については、次の場所を参照してください。
http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#mapfunc