web-dev-qa-db-ja.com

mod_rewriteの非表示機能

最近、mod_rewriteスレッドのかなりの数が浮かんでいるように見えます。その結果、一般的な機能に関するいくつかのメモと、おそらくいくつかの迷惑なニュアンスをまとめました。

mod_rewriteを使用して他にどのような機能/一般的な問題が発生していますか?

119
Owen

Mod_rewriteルールを配置する場所

mod_rewriteルールは、httpd.confファイル内、または.htaccessファイル内に配置できます。 httpd.confにアクセスできる場合、ここにルールを配置するとパフォーマンスが向上します(.htaccessファイルが呼び出されるたびにルールが1回処理されるため)。

Mod_rewriteリクエストのロギング

ロギングは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 も使用できます。

  2. 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]
    
  3. SSLの強制

    RewriteEngine on
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://example.com/$1 [R,L]
    
  4. 一般的なフラグ:

    • [R]または[redirect]-リダイレクトを強制する(デフォルトは302一時リダイレクト)
    • [R=301]または[redirect=301]-301の永続的なリダイレクトを強制する
    • [L]または[last]-書き換えプロセスを停止します(一般的な落とし穴については以下の注を参照してください)
    • [NC]または[nocase]-マッチングで大文字と小文字を区別しないことを指定します


    複数のフラグをコンマで区切ることができます。

    RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
    

よくある落とし穴

  1. 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_aliasmod_rewriteを混在させることができますが、上記の基本的なリダイレクトを処理するだけでなく、より多くの作業が必要になります。

  2. コンテキストは構文に影響します

    .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
    
  3. [L]は最後ではありません! (時々)

    [L]フラグは、それ以上の書き換えルールの処理を停止しますそのルールセットをパススルーするため。ただし、URLがそのパスで変更され、.htaccessコンテキストまたは<Directory>セクションにいる場合、変更された要求はURL解析エンジンを介して再び返されます。次のパスでは、今回は別のルールに一致する可能性があります。これを理解していない場合、[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]フラグの代わりに[L]フラグ( Apache docsを参照 )を使用することです。その後のパス)。ただし、[END]フラグはApache v2.3.9 +でのみ使用できるため、v2.2以前を使用している場合は、 [L]フラグだけで立ち往生しています。

    以前のバージョンでは、RewriteCondステートメントを使用して、URL解析エンジンの後続のパスでルールが一致しないようにする必要があります。

    # Only process the following RewriteRule if on the first pass
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule ...
    

    または、RewriteRuleが、リクエストの再解析を引き起こさないコンテキスト(つまりhttpd.conf)にあることを確認する必要があります。

203
Owen

.htaccessで発生する内部リダイレクト/書き換えを「ブロック」する必要がある場合は、

RewriteCond %{ENV:REDIRECT_STATUS} ^$

ここで説明 のような条件。

21
mromaine

RewriteBaseとの取引:

ほとんどの場合、RewriteBaseを設定する必要があります。そうしないと、Apacheはベースがディレクトリへの物理ディスクパスであると推測します。だからこれから始めましょう:

RewriteBase /
18
Sean McMillan

その他の落とし穴:

1-場合によっては、MultiViewsを無効にすることをお勧めします

Options -MultiViews

MultiViewsのすべての機能について詳しくはありませんが、アクティブなときにmod_rewriteルールが台無しになることは知っています。そのプロパティの1つは、探していると思われるファイルの拡張子を試して「推測」することです。

説明します:Web dirに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について知っていたと思うすべてのものに疑問を投げかけています。次に、この新しい状況の背後にあるロジックの意味を理解しようとするルールをいじり始めますが、テストするほど意味が少なくなります。

OK、要するに、mod_rewriteをロジックに近い方法で動作させたい場合、MultiViewsをオフにすることは正しい方向への一歩です。

2- FollowSymlinksを有効にする

Options +FollowSymLinks 

それについては、私は実際には詳細を知りませんが、何度も言及されているのを見てきました。

13
Michael Ekoka

等式は次の例で行うことができます:

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]
5
DrDol

[L]フラグの理解を深めることが適切です。 [L]フラグis最後に、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]フラグdoesは、-の書き換えルールの処理を停止しますそのパスルールセットを通して。ただし、[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)にあることを確認する必要があります。

4
JaredC

もう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

3
B.E.

mod_rewriteは、URLを変更せずにリクエスト処理の側面を変更できます。環境変数の設定、Cookieの設定など。これは非常に便利です。

環境変数を条件付きで設定します。

RewriteCond %{HTTP_COOKIE} myCookie=(a|b) [NC]
RewriteRule .* - [E=MY_ENV_VAR:%b]

503応答を返します:RewriteRule 's [R]フラグは3xx以外の値を取り、リダイレクトしない応答を返すことができます。管理されたダウンタイム/メンテナンスの場合:

RewriteRule .* - [R=503,L]

503応答を返します(リダイレクト自体ではありません)。

また、mod_rewriteはmod_proxyへの強力なインターフェイスのように動作するため、ProxyPassディレクティブを記述する代わりにこれを行うことができます。

RewriteRule ^/(.*)$ balancer://cluster%{REQUEST_URI} [P,QSA,L]

意見:RewriteRulesとRewriteCondsを使用して、要求の考えられるあらゆる側面に基づいて、異なるアプリケーションまたはロードバランサーに要求をルーティングすることは、非常に強力です。バックエンドに向かう途中でリクエストを制御し、戻る途中でレスポンスを変更できるため、mod_rewriteはすべてのルーティング関連の設定を一元化する理想的な場所になります。

それを学ぶために時間をかけて、それはそれだけの価値があります! :)

2
cweekly