Apache的rewrite規則詳細介紹

rewrite標誌

R[=code](force redirect) 強制外部重定向
強制在替代字符串加上http://thishost[:thisport]/前綴重定向到外部的URL.如果code不指定,將用缺省的302 HTTP狀態碼。
F(force URL to be forbidden)禁用URL,返回403HTTP狀態碼。
G(force URL to be gone) 強制URL爲GONE,返回410HTTP狀態碼。
P(force proxy) 強制使用代理轉發。
L(last rule) 表明當前規則是最後一條規則,停止分析以後規則的重寫。
N(next round) 重新從第一條規則開始運行重寫過程。
C(chained with next rule) 與下一條規則關聯
如果規則匹配則正常處理,該標誌無效,如果不匹配,那麼下面所有關聯的規則都跳過。
T=MIME-type(force MIME type) 強制MIME類型
NS (used only if no internal sub-request) 只用於不是內部子請求
NC(no case) 不區分大小寫
QSA(query string append) 追加請求字符串
NE(no URI escaping of output) 不在輸出轉義特殊字符
例如:RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE] 將能正確的將/foo/zoo轉換成/bar?arg=P1=zed
PT(pass through to next handler) 傳遞給下一個處理
例如:
RewriteRule ^/abc(.*) /def$1 [PT] # 將會交給/def規則處理
Alias /def /ghi
S=num(skip next rule(s)) 跳過num條規則
E=VAR:VAL(set environment variable) 設置環境變量

rewrite時服務器變量:
HTTP headers:HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE, HTTP_HOST, HTTP_ACCEPT
connection & request: REMOTE_ADDR, QUERY_STRING
server internals: DOCUMENT_ROOT, SERVER_PORT, SERVER_PROTOCOL
system stuff: TIME_YEAR, TIME_MON, TIME_DAY

Rewrite規則表達式的說明:
. 匹配任何單字符
[chars] 匹配字符串:chars
[^chars] 不匹配字符串:chars
text1|text2 可選擇的字符串:text1或text2
? 匹配0到1個字符
* 匹配0到多個字符
+ 匹配1到多個字符
^ 字符串開始標誌
$ 字符串結束標誌
\n 轉義符標誌

反向引用 $N 用於 RewriteRule 中匹配的變量調用(0 <= N <= 9)
反向引用 %N 用於 RewriteCond 中最後一個匹配的變量調用(1 <= N <= 9)

RewriteCond標誌符
'nocase|NC'(no case)忽略大小
'ornext|OR' (or next condition)邏輯或,可以同時匹配多個RewriteCond條件

RewriteRule適用的標誌符
'redirect|R [=code]' (force redirect)強迫重寫爲基於http開頭的外部轉向(注意URL的變化) 如:[R=301,L]
'forbidden|F' (force URL to be forbidden)重寫爲禁止訪問
'proxy|P' (force proxy)重寫爲通過代理訪問的http路徑
'last|L' (last rule)最後的重寫規則標誌,如果匹配,不再執行以後的規則
'next|N' (next round)循環同一個規則,直到不能滿足匹配
'chain|C' (chained with next rule)如果匹配該規則,則繼續下面的有Chain標誌的規則。
'type|T=MIME-type' (force MIME type)指定MIME類型
'nosubreq|NS' (used only if no internal sub-request)如果是內部子請求則跳過
'nocase|NC' (no case)忽略大小
'qsappend|QSA' (query string append)附加查詢字符串
'noescape|NE' (no URI escaping of output)禁止URL中的字符自動轉義成%[0-9]+的形式。
'passthrough|PT' (pass through to next handler)將重寫結果運用於mod_alias
'skip|S=num' (skip next rule(s))跳過下面幾個規則
'env|E=VAR:VAL' (set environment variable)添加環境變量

實際操作

例子:
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} ^MSIE [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^Opera [NC]
RewriteRule ^.* - [F,L] 這裏”-”表示沒有替換,瀏覽器爲IE和Opera的訪客將被禁止訪問。

例子:
RewriteEngine On
RewriteBase /test
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ([^/]+)$ /test/$1.php
#for example: /test/admin => /test/admin.php
RewriteRule ([^/]+)\.html$ /test/$1.php [L]
#for example: /test/admin.html => /test/admin.php

限制目錄只能顯示圖片
< IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !^.*\.(gif|jpg|jpeg|png|swf)$
RewriteRule .*$ - [F,L]
< /IfModule>

Apachemod_rewrite是提供了強大URL操作的殺手級模塊,可以實現幾乎所有你夢想的URL操作,其代價是你必須接受其複雜性,因爲mod_rewrite對於初學者的主要障礙就是不容易理解和運用,即使是Apache專家有時也會發掘出mod_rewrite的新用途。換句話說:你或者是打退堂鼓永不再用,或者是喜歡它並一生受用。目前存在這樣一種傾向:許多初學者只是把URL重寫規則當着是會變戲法的魔咒,而並未在使用中真正理解這些規則的含義。

 

本篇文檔試圖給出充分的背景知識,以便於初學者隨後的理解,而不是盲目的複製和粘貼。

mod_rewrite使用的是Perl兼容的正則表達式語法。本文不打算詳細講解正則表達式語法,你可以到PCRE man page, Perl regular expression man page, Mastering Regular Expressions, by Jeffrey Friedl獲得這些內容。

 

RewriteRule指令的說明部分有一個簡單的正則表達式語法簡介,可以去參考一下。

另外需要說明的是可以在表達式的最前面加上一個感嘆號('!')表示不匹配,不過這種用法並不符合正則表達式語法。

正則表達式的反向引用能力

 

這是很重要的一點:一旦在Pattern或者CondPattern中使用了圓括號,就會建立內部的反向引用,可以使用$N%N來調用(見下述),並且在SubstitutionTestString中都有效。圖-2說明了反向引用被轉換和展開的位置。

 

 

-2: The back-reference flow through a rule.

 

內部處理

 

此模塊的內部處理極爲複雜,但是爲了使一般用戶避免犯低級錯誤,也讓管理員能充分利用其功能,在此仍然做一下說明。

 

API階段

 

首先,你必須瞭解Apache是分若干階段來處理HTTP請求的。Apache API對每個階段都提供了一個hook程序。mod_rewrite使用兩個hook程序:其一,從URL到文件名的轉換hook(用在讀取HTTP請求之後、授權開始之前) 其二,修正hook(用在授權階段和讀取目錄級配置(.htaccess)之後、內容處理器激活之前)

 

所以,Apache收到一個請求並且確定了響應主機(或虛擬主機)之後,重寫引擎即開始處理服務器級配置中的所有mod_rewrite指令(此時處於從URL到文件名轉換的階段),此階段完成後,最終的數據目錄便確定了。接下來進入修正程序段並觸發目錄級配置中的mod_rewrite指令。這兩個階段並不是涇渭分明的,但都實施了把URL重寫成新的URL或者文件名。雖然API最初不是爲此目的而設計的,但是現在它已經成爲了API的一種用途。記住以下兩點,會有助於更好地理解:

雖然mod_rewrite可以將URL重寫爲新的URL或文件名,甚至將文件名重寫爲新的文件名,但是之前的API只提供從URL到文件名的hook。在Apache 2.0中,增加了兩個丟失的hook以使得處理過程更加清晰。不過這樣做並沒有給用戶帶來麻煩,用戶只需記住這樣一個事實:藉助從URL到文件名的hook比最初API設計的目標功能更強大。

令人難以置信的是,mod_rewrite還提供了目錄級的URL操作(.htaccess文件),而這些文件必須在將URL轉換成文件名之後纔會被處理(這是必須的,因爲.htaccess存在於文件系統中)。換句話說,根據API階段,這時再處理任何URL操作已經太晚了。爲了解決這個"雞和蛋"的問題,mod_rewrite使用了一個小技巧:在進行一個目錄級的URL/文件名操作時,先把文件名重寫回相應的URL(通常這個操作是不可行的,但是參考下面的RewriteBase指令就能明白它是怎麼實現的了),然後,對這個新的URL建立一個新的內部的子請求,再重新開始API階段的執行。

 

另外,mod_rewrite盡力使這些複雜的操作對用戶透明。但仍須記住:服務器級的URL操作速度快而且效率高,而目錄級的操作由於這個"雞和蛋"的問題速度較慢而且效率也低。但從另一個側面看,這卻是mod_rewrite得以爲一般用戶提供(局部限制的)URL操作的唯一方法。

 

牢記這兩點!

 

規則集的處理

 

mod_rewrite在這兩個API階段中開始執行時,它會讀取配置結構中配置好的 (或者是在服務啓動時建立的服務器級的,或者是在遍歷目錄採集到的目錄級的)規則集,然後,啓動URL重寫引擎來處理(帶有一個或多個條件的)規則集。無論是服務器級的還是目錄級的規則集,都是由同一個URL重寫引擎處理,只是最終結果處理不同而已。

 

規則集中規則的順序是很重要的,因爲重寫引擎是按一種特殊的順序處理的:逐個遍歷每個規則(RewriteRule指令),如果出現一個匹配條件的規則,則可能回頭遍歷已有的規則條件(RewriteCond指令)。由於歷史的原因,條件規則是前置的,所以控制流程略顯冗長,細節見圖-1

 

 

-1:重寫規則集中的控制流

 

可見,URL首先與每個規則的Pattern匹配,如果匹配失敗,mod_rewrite將立即終止此規則的處理,繼而處理下一個規則。如果匹配成功,mod_rewrite將尋找相應的規則條件,如果一個條件都沒有,則簡單地用Substitution構造的新值來替換URL,然後繼續處理其他規則;但是如果條件存在,則開始一個內部循環按其列出的順序逐個處理。對規則條件的處理有所不同:URL並不與模式進行匹配,而是首先通過擴展變量、反向引用、查找映射表等步驟建立一個TestString字符串,然後用它來與CondPattern匹配。如果匹配失敗,則整個條件集和對應的規則失敗;如果匹配成功,則執行下一個規則直到所有條件執行完畢。如果所有條件得以匹配,則以Substitution替換URL,並且繼續處理。

 

例如下面的配置

RewriteEngine on 

#設置Rewrite日誌

RewriteLogLevel 9

RewriteLog "C:/Apache/logs/rewrite.log"

 

RewriteCond $1   ^(.*)/.(.*) [NC]                  1

RewriteCond %{HTTP_HOST}   !^(.*)/.(.*)/.(.*)      2

     

RewriteRule ^/(.*)         /$1?ID=%1               3

 

#RewriteCond ...............                              4

#RewriteRule ^/(.*) ............                            5

 

假設在瀏覽器中輸入 http://www.domain.com/index.php,服務器端將會進行如下操作

規則集合的執行:逐個遍歷每個規則(RewriteRule指令),發現第(3)行,則用輸入 /index.php作爲RewriteRulePattern進行匹配,如果匹配不成功,則會繼續往下處理其他的RewriteRule。如果成功,則會去尋找本條RewriteRule前面的全部RewriteCond,然後從第找到的第一個RewriteCond開始,建立TestString字符串,然後用它來與CondPattern匹配。如果匹配失敗,則整個條件集和對應的規則失敗;如果匹配成功,則執行下一個規則直到所有條件執行完畢。如果所有條件得以匹配,則以Substitution替換URL,並且繼續處理。

 

上面的例子,如果執行到(5),則只會有(4)這個RewriteCond被處理,(3)前面的(1)(2)不會再次被處理,如果開始執行的時候(3RewriteRule沒有匹配,則(1)(2)就不會有被執行的機會。

 

反向引用:

從前面的例子和上面的圖可以看出,

Substitution可以反向引用當前Pattern中的匹配的分組成分(圓括號!)

引用方法是: $N  (0 <= N <= 9)

也可以反向應用RewriteCond條件中最後符合的條件中的分組成分(圓括號!)。記住是最後一個匹配成功的。

引用方法是: %N  (1 <= N <= 9)

 

同樣,TestString中可以包含反向引用當前匹配的RewriteRulePattern部分的匹配的分組成分(圓括號!)

引用方法是: $N  (0 <= N <= 9)

從處理圖看,只能對該RewriteCond前面的被成功處理過的CondPattern分組成分(圓括號!)進行引用,即條件(2)可以對(1)進行反向引用。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章