mod_rewriteの隠された機能


119

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

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


回答:


203

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. すべてのリクエストを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]フラグ(Apache docsを参照)を使用する[L]ことです。ただし、この[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)内にあり、リクエストが再解析されないようにする必要があります。


10
おい、完全にインターネット上で最高の記事は今mod書き換え。私はそれが嫌いです。私はmod_rewriteがどれだけ嫌いかという理由でlighttpd異端者です。
ケントフレドリック

3
これは、これまでにmod_rewriteで見つけた最も有用なガイドでした。RewriteLogについて知るだけで非常に多くの問題が解決され、追跡に何日もかかっていたものが数分になりました。(つまり、ルールは作成されましたが、なぜ機能しないのか理解できませんでした)
Joe Chin

1年前の投稿ですが、私がSOで見つけた最も有用なものの1つです。
Erik

3
[L]フラグはルールがあることを意味し、最後彼らは内部リダイレクトされているので、あなたはので、これは、書き換え停止しません、現在処理中dirBに適用されるdirC次のhtaccessの処理に。単独でRewriteRule ^(.*)$ index.php?query=$1は、内部リダイレクトの無限ループになります(実際には、10回の反復で終了します)。-1は、[L]が最後ではないことを示唆しているためです。書き換えプロセスを終了するわけではありませんが、最後です。
kbec、

3
私は信じているRewriteCond %{HTTPS} off(HTTPSへの非SSLトラフィックを強制的にあなたの例で)HTTPS接続をチェックするための望ましい方法です
Madbreaks

22

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

RewriteCond %{ENV:REDIRECT_STATUS} ^$

ここで説明するように、状態。


ありがとう、それで問題が解決しました!
マシュー

ライフセーバーもありがとう!
ベンジャミン

これは確かに命の恩人です!人々はそのことにもっと気づくべきです。実際に、私はほぼすべての質問にこれを提案するつもりだ.*[L]私はここに来た前に私が読んフラグ。
Qwerty、2014年

私はこれにいくつかの変更を見てきました200!=200^.^$。どうやら、変数は200リダイレクト用に設定されますが、他のページ(エラーなど)もそれを何らかの値に設定します。これis emptyis not emptyis 200必要is not 200に応じて、、、またはのいずれかを確認することを意味します。
Qwerty、2014年

18

RewriteBaseとの取引:

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

RewriteBase /

ああ。これで、私が抱えていた問題は完全に修正されました。それをありがとう!
トムサベージ

3
の言い方RewriteBase .、または指定したものを変更するだけでURLを同じに保つ必要があることを示すものはありますか?
ジェイK

ありがとう、これは貴重な情報でした。:)
AturSams

2
ディレクティブRewriteBaseで相対パス置換を使用している場合にのみ設定する必要がありますRewriteRule。相対パスを使用しないことをお勧めします。
MrWhite、2015年

2
私はこの答えに同意しません。私たちのRewriteBase開発チームでは、ほぼすべての開発者がそれが何をしているのか誤解しているので、私たちは完全に回避しています。@ w3dが言ったように、文字を保存し、同じベースを1つのファイル内のすべてのRewriteRulesに適用する場合にのみ必要です。あなたがそれを避ければあなたのコードはおそらく他の人にとってより明確になるでしょう。
Simon East

13

その他の落とし穴:

1-時には、マルチビューを無効にすることをお勧めします

Options -MultiViews

私はすべてのMultiViews機能に精通していませんが、アクティブなときにmod_rewriteルールを台無しにすることを知っています。 。

説明します。Webディレクトリに2つのphpファイル、file1.phpとfile2.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を論理に近い方法で機能させたい場合、MultiViewをオフにすることは正しい方向への一歩です。

2- FollowSymlinksを有効にする

Options +FollowSymLinks 

その1つ、私は本当に詳細はわかりませんが、何度も言及されているのを見てきました。


ありがとう:) / log / activityが/log.txt/activityに変わるような予期せぬ驚きに気づきました。ヒントをありがとう:) .. facebookですべての女性の同僚を誤って誘惑するなど、あまりにも悪いコンピュータは決して予期しないことを起こしません。 :)
AturSams

1
+FollowSymLinksmod_rewriteあいまいなセキュリティ上の理由から、ドキュメントでは、がまったく機能することが必須であると記載されています。
ジョーイ

ここでの2つのステートメントは非常に私を心配しています:「私はすべてのMultiViews機能に精通していませんが、アクティブなときにmod_rewriteルールを台無しにすることを知っています」とこれは「それは、私は本当に詳細がわからない」 、しかし私はそれが何度も言及されているのを見たので、それをしてください。私はあなたのような人々があなたがわからないことについてSOに答えを書かないことを望みます。
TheCarver 2013

1
@PaparazzoKid:SOを百科事典と間違えていると思います。それは、彼らが協力している技術についての理解を結びつけるために集まる人々のコミュニティです。あなたの前のAWホワイトとジョーイとは異なり、あなたのコメントはほとんど価値がありません。MVとFSLは多くのApacheのオプションの2つです。私の答えは、mod_rw、特に別のモジュールを操作する際の落とし穴についてです。これは、一部のオプションと競合し、他のオプションと連携します。MVがmod_rwにどのように影響するかを説明し、+ FSLが一般的な推奨事項であることを述べました。ジョーイはそれが実際に義務的であることを確認しました。あなたは何を持っていきますか?
Michael Ekoka 2013年

ありがとう。私は1時間のほとんどを費やして、レガシーサイトを機能させ、書き換えルールをデバッグしようとしましたが、MultiViewsがすべてを上書きしていることがわかりました。
Andrew McCombe 2014年

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]

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)内にあり、リクエストが再解析されないようにする必要があります。


3

もう1つの優れた機能は、rewrite-map-expansionsです。あなたがホストの膨大な量/処理のための書き換えを持っている場合、それらは特に便利です:

これらは、Key-Value-Replacementのようなものです。

RewriteMap examplemap txt:/path/to/file/map.txt

次に、次のようなルールでマッピングを使用できます。

RewriteRule ^/ex/(.*) ${examplemap:$1}

このトピックの詳細については、こちらをご覧ください。

http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#mapfunc


.htaccessベースの書き換えを使用している場合は、この機能を無視してください。このコンテキストでは機能しません。
TerryE 2012年

2
RewriteMapディレクティブはサーバーコンテキスト(httpd.conf)で使用する必要がありますが、そこで定義すると、.htaccessファイルのRewriteRuleを介してマップを使用できます。
JaredC 2014年

2

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

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

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

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

RewriteRule .* - [R=503,L]

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

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

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

意見:RewriteRulesとRewriteCond sを、リクエストの事実上考えられるあらゆる側面に基づいてリクエストを異なるアプリケーションまたはロードバランサーにルーティングすることは、非常に強力です。バックエンドに向かう途中で要求を制御し、戻るときに応答を変更できるため、mod_rewriteはルーティング関連のすべての構成を集中管理するのに理想的な場所になります。

時間をかけて習得してください。それだけの価値があります。:)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.