119

最近、かなりの数のmod_rewriteスレッドが浮かんでいるようですが、その特定の側面がどのように機能するかについて少し混乱しています。その結果、私は一般的な機能に関するいくつかのメモと、おそらくいくつかの厄介なニュアンスをまとめました。

他にどのような機能/一般的な問題を使用して遭遇しましたmod_rewriteか?

4

8 に答える 8

203

mod_rewriteルールを配置する場所

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

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. すべてのリクエストを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_alias:と組み合わせることができますがmod_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が変更され、コンテキストまたはセクションにいる場合、変更されたリクエストは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、リクエストが再解析されないコンテキスト(つまり)にあることを確認する必要があります。

于 2008-11-13T01:15:42.970 に答える
22

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

RewriteCond %{ENV:REDIRECT_STATUS} ^$

ここで説明されているように、状態。

于 2010-04-22T06:05:22.997 に答える
18

RewriteBase との契約:

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

RewriteBase /
于 2009-08-27T03:07:26.327 に答える
13

その他の落とし穴:

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 

あれ、詳しくはよくわからないけど、何度も言ってるのを見たからやってみよう。

于 2009-08-19T10:08:10.930 に答える
5

方程式は次の例で実行できます。

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]
于 2010-01-19T21:42:26.580 に答える
4

[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) にあることを確認する必要があります。

于 2014-11-14T12:25:23.070 に答える
3

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

于 2009-08-19T10:18:10.787 に答える