歡迎您光臨本站 註冊首頁

mod_rewrite 詳解

←手機掃碼閱讀     火星人 @ 2014-03-05 , reply:0

mod_rewrite 詳解

Apache模塊 mod_rewrite

    mod_rewrite模塊提供了一個基於規則的(使用正則表達式分析器的)實時轉向URL請求的引擎。 支持每個規則可以擁有不限數量的規則以及附加條件規則的靈活而且強大的URL操作機制。 此URL操作可以取決於各種測試,比如伺服器變數、環境變數、HTTP頭、時間標記, 甚至各種格式的用於匹配URL組成部分的查找資料庫。

    mod_rewrite模塊可以操作URL的所有部分(包括路徑信息部分), 在伺服器級的(httpd.conf)和目錄級的(.htaccess)配置都有效, 還可以生成最終請求串。此重寫操作的結果可以是內部子處理,也可以是外部請求的轉向, 甚至還可以是內部代理處理。

    但是,所有這些功能和靈活性帶來一個問題,那就是複雜性, 因此,不要指望一天之內就能看懂整個模塊。


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

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

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

雖然mod_rewrite可以重寫URL為URL,重寫URL為文件名, 甚至重寫文件名為文件名,但是目前API只提供一個URL到文件名的hook。 在Apache 2.0 中,增加了兩個丟失hook以使處理過程更清晰。 但是,這樣做並沒有給用戶帶來麻煩,只需記住這樣一個事實: Apache藉助URL到文件名的hook而比API設計的目標功能更強大。
難以置信的是,mod_rewrite提供了目錄級的URL操作,即,.htaccess文件, 而這些文件必須在URL轉換成文件名以後的較多步驟完成之後才會被處理。 這也是必須的,因為.htaccess文件存在於文件系統中,所以處理已經到達這個層面。 換句話說,根據API程序段,這時再處理任何URL操作已經太晚了。 為了解決這個雞和蛋的問題,mod_rewrite使用了一個技巧: 在進行一個目錄級的URL/文件名的操作時,mod_rewrite先把文件名重寫回相應的URL (通常這個操作是不可行的,但是參考下面的RewriteBase指令就明白它是怎麼實現的), 然後,對這個新的URL建立一個新的內部的子請求,以此重新開始API程序段的執行。
另外,mod_rewrite儘力使這些複雜的操作對用戶全透明,但仍須記住: 伺服器級的URL操作速度快而且效率高,而目錄級的操作由於這個雞和蛋的問題速度慢效率也低。 但從另一個側面看,這卻是mod_rewrite得以為一般用戶提供(局部限制的)URL操作的唯一方法。

牢記這兩點!

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

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


Figure 1:The control flow through the rewriting ruleset

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

特殊字元的引用
在Apache 1.3.20, TestString and Substitution 字元串中的特殊字元可以用前綴的斜杠來實現轉義(即,忽略其特殊含義而視之為普通字元)。 比如,Substitution可以用'\$'來包含一個美元符號, 以避免mod_rewrite把它視為反向引用。

正則表達式的反向引用能力
這是很重要的一點:一旦在Pattern或者CondPattern使用了圓括弧, 就會建立內部的反向引用,可以使用$N和%N來調用(見下述), 並且,在Substitution和TestString中都有效。 Figure 2 說明了反向引用被轉換擴展的位置。


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

雖然mod_rewrite內部處理的這個過程是比較雜亂的, 但是了解這些可以幫助你閱讀下文中指令的講述。


環境變數
mod_rewrite模塊會跟蹤兩個額外的(非標準的)CGI/SSI環境變數, SCRIPT_URL和SCRIPT_URI。 他們包含了當前資源的邏輯的網路狀態, 而標準的CGI/SSI變數SCRIPT_NAME和 SCRIPT_FILENAME包含的是物理的系統狀態。

注意: 這些變數保持的是其最初被請求時的URI/URL, 即, 在任何重寫操作之前的。 其重要性在於他們是重寫操作重寫URL到物理路徑名的原始依據。

舉例
SCRIPT_NAME=/sw/lib/w3s/tree/global/u/rse/.www/index.html
SCRIPT_FILENAME=/u/rse/.www/index.html
SCRIPT_URL=/u/rse/
SCRIPT_URI=http://en1.engelschall.com/u/rse/


實用方案
我們還提供另外一個文檔URL Rewriting Guide, 列舉了許多基於URL的問題的實用方案,其中你可以找到真實有用的規則集和mod_rewrite的更多信息。


RewriteBase 指令

RewriteBase指令顯式地設置了目錄級重寫的基準URL。 在下文中,你可以看見RewriteRule可以用於目錄級的配置文件中(.htaccess), 並在局部範圍內起作用,即,規則實際處理的只是剝離了本地路徑前綴的一部分。 處理結束后,這個路徑會被自動地附著回去。 默認值是,RewriteBase physical-directory-path

在對一個新的URL進行替換時,mod_rewrite模塊必須把這個URL重新注入到伺服器處理中。 為此,它必須知道其對應的URL前綴或者說URL基準。通常,此前綴就是對應的文件路徑。 但是,大多數網站URL不是直接對應於其物理文件路徑的,因而一般不能做這樣的假定! 所以在這種情況下,就必須用RewriteBase指令來指定正確的URL前綴。

如果你的網站伺服器URL不是與物理文件路徑直接對應的, 而又需要使用RewriteRule指令, 則必須在每個對應的.htaccess文件中指定RewriteBase。
舉例,目錄級配置文件內容如下:

#
#  /abc/def/.htaccess -- per-dir config file for directory /abc/def
#  Remember: /abc/def is the physical path of /xyz, i.e., the server
#            has a 'Alias /xyz /abc/def' directive e.g.
#

RewriteEngine On

#  let the server know that we were reached via /xyz and not
#  via the physical path prefix /abc/def
RewriteBase   /xyz

#  now the rewriting rules
RewriteRule   ^oldstuff\.html$  newstuff.html

上述例子中,對/xyz/oldstuff.html 的請求被正確地重寫為物理的文件/abc/def/newstuff.html.

For Apache Hackers
以下列出了內部處理的詳細步驟:

Request:
   /xyz/oldstuff.html

Internal Processing:
   /xyz/oldstuff.html     ->; /abc/def/oldstuff.html  (per-server Alias)
   /abc/def/oldstuff.html ->; /abc/def/newstuff.html  (per-dir    RewriteRule)
   /abc/def/newstuff.html ->; /xyz/newstuff.html      (per-dir    RewriteBase)
   /xyz/newstuff.html     ->; /abc/def/newstuff.html  (per-server Alias)

Result:
   /abc/def/newstuff.html

雖然這個過程看來很繁複,但是由於目錄級重寫的到來時機已經太晚了, 它不得不把這個(重寫)請求重新注入到Apache核心中,所以Apache內部確實是這樣處理的。 但是:它的開銷並不象看起來的那樣大,因為重新注入完全在Apache伺服器內部進行, 而且這樣的過程在Apache內部也為其他許多操作所使用。 所以,你可以充分信任其設計和實現是正確的。


RewriteCond 指令

RewriteCond指令定義了一個規則的條件,即,在一個RewriteRule指令之前有一個或多個RewriteCond指令。 條件之後的重寫規則僅在當前URI與pattern匹配並且符合這些條件的時候才會起作用。

TestString是一個純文本的字元串,但是還可以包含下列可擴展的成分:

RewriteRule反向引用: 引用方法是
$N

(0 <= N <= 9) 引用當前(帶有若干RewriteCond指令的)RewriteRule中的 與pattern匹配的分組成分(圓括弧!)。
RewriteCond反向引用: 引用方法是
%N

(1 <= N <= 9) 引用當前若干RewriteCond條件中最後符合的條件中的分組成分(圓括弧!)。
RewriteMap 擴展: 引用方法是
${mapname:key|default}

細節請參見the documentation for RewriteMap。
伺服器變數: 引用方法是
%{ NAME_OF_VARIABLE }

NAME_OF_VARIABLE可以是下表列出的字元串之一: HTTP headers: connection & request:  
HTTP_USER_AGENT
HTTP_REFERER
HTTP_COOKIE
HTTP_FORWARDED
HTTP_HOST
HTTP_PROXY_CONNECTION
HTTP_ACCEPT
REMOTE_ADDR
REMOTE_HOST
REMOTE_USER
REMOTE_IDENT
REQUEST_METHOD
SCRIPT_FILENAME
PATH_INFO
QUERY_STRING
AUTH_TYPE
  
server internals: system stuff: specials:
DOCUMENT_ROOT
SERVER_ADMIN
SERVER_NAME
SERVER_ADDR
SERVER_PORT
SERVER_PROTOCOL
SERVER_SOFTWARE
TIME_YEAR
TIME_MON
TIME_DAY
TIME_HOUR
TIME_MIN
TIME_SEC
TIME_WDAY
TIME
API_VERSION
THE_REQUEST
REQUEST_URI
REQUEST_FILENAME
IS_SUBREQ


這些都對應於類似命名的HTTP MIME頭、Apache伺服器的C變數以及Unix系統中的 struct tm欄位,大多數都在其他的手冊或者CGI規範中有所講述。 而其中為mod_rewrite所特有的變數有:

IS_SUBREQ
如果正在處理的請求是一個子請求,它包含字元串"true",否則就是"false"。 模塊為了解析URI中的附加文件,有可能會產生子請求。
API_VERSION
這是正在使用的httpd中(伺服器和模塊之間內部介面)的Apache模塊API的版本, 其定義位於include/ap_mmn.h中。mod_rewrite模塊版本對應於正在使用的Apache的版本 (比如,在Apache 1.3.14的發行版中,這個值是19990320:10)。 通常,對它感興趣的是模塊的作者。
THE_REQUEST
這是由瀏覽器發送給伺服器的完整的HTTP請求行。(比如, "GET /index.html HTTP/1.1"). 它不包含任何瀏覽器發送的附加頭信息。
REQUEST_URI
這是在HTTP請求行中所請求的資源。(比如上述例子中的"/index.html".)
REQUEST_FILENAME
這是與請求相匹配的完整的本地文件系統的文件路徑名或描述.
特別注意事項:

SCRIPT_FILENAME和REQUEST_FILENAME包含的值是相同的,即, Apache伺服器的內部request_rec結構中的filename欄位。 第一個其實就是大家都知道的CGI變數名,而第二個則是( 包含了request_rec結構中的uri欄位的)REQUEST_URI的一個副本,
特殊形式: %{ENV:variable} 其中的variable可以是任何環境變數。 它是通過查找Apache內部結構得到的, 或者(如果沒找到的話)是由Apache伺服器進程通過getenv()得到的。
特殊形式: %{HTTP:header} 其中的header可以是任何HTTP MIME頭的名稱。 它是通過查找HTTP請求得到的。比如: %{HTTP:Proxy-Connection}就是HTTP頭 ``Proxy-Connection:''的值.
特殊形式 %{LA-U:variable} 它是一個預設的值, variable的最終值在執行一個內部的(基於URL的)子請求后決定。 在重寫需要使用一個尚未有效的但是會在之後的API程序段中設置的變數的時候,就會使用這個方法。 比如,需要在伺服器級配置(httpd.conf文件)中重寫REMOTE_USER變數, 則,必須使用%{LA-U:REMOTE_USER},因為此變數是由認證程序段設置的, 而這個程序段是在mod_rewrite所在的URL轉譯程序段之後才執行的。 但是,因為mod_rewrite是通過API修正程序段來實現目錄級(.htaccess file)配置的, 而這個程序段在認證程序段之前就執行了,所以用%{REMOTE_USER}就可以了。
特殊形式: %{LA-F:variable} 它是一個預設的值, variable的最終值在執行一個內部的(基於文件名的)子請求后決定。 大多數情況下和上述的LA-U是相同的.
CondPattern是條件pattern, 即, 一個應用於當前實例TestString的正則表達式, 即, TestString將會被計算然後與CondPattern匹配.

謹記: CondPattern是一個兼容perl的正則表達式, 但是還有若干增補:

可以在pattern串中使用'!' 字元(驚嘆號)來實現匹配的反轉。
CondPatterns有若干特殊的變種。除了正則表達式的標準用法,還有下列用法:
'<CondPattern' (詞典順序的小於)
將CondPattern視為純字元串,與TestString以詞典順序相比較. 如果按詞典順序,TestString小於CondPattern,則為真.
'>;CondPattern' (詞典順序的大於)
將CondPattern視為純字元串,與TestString以詞典順序相比較. 如果按詞典順序,TestString大於CondPattern,則為真.
'=CondPattern' (詞典順序的等於)
將CondPattern視為純字元串,與TestString以詞典順序相比較. 如果按詞典順序,TestString等於CondPattern,則為真,即, 兩個字元串(逐個字元地)完全相等。如果CondPattern只是""(兩個引號), 則TestString將與空串相比較.
'-d' (是一個目錄)
將TestString視為一個路徑名並測試它是否存在而且是一個目錄.
'-f' (是一個常規的文件)
將TestString視為一個路徑名並測試它是否存在而且是一個常規的文件.
'-s' (是一個非空的常規文件)
將TestString視為一個路徑名並測試它是否存在而且是一個尺寸大於0的常規的文件.
'-l' (是一個符號連接)
將TestString視為一個路徑名並測試它是否存在而且是一個符號連接.
'-F' (對子請求有效的業已存在的文件)
測試TestString是否一個有效的文件, 而且可以被伺服器當前已經配置的所有存取控制所存取。 它用一個內部子請求來做判斷,由於會降低伺服器的性能,請小心使用!
'-U' (對子請求有效的業已存在的URL)
測試TestString是否一個有效的URL, 而且可以被伺服器當前已經配置的所有存取控制所存取。 它用一個內部子請求來做判斷,由於會降低伺服器的性能,請小心使用!
注意
所有這些測試都可以用驚嘆號作前綴('!')以實現條件的反轉.
另外,還可以為CondPattern追加特殊的標記



作為RewriteCond指令的第三個參數。 Flags是一個以逗號分隔的以下標記的列表:

'nocase|NC' (no case)
它使測試忽略大小寫, 即, 擴展后的TestString和CondPattern中, 'A-Z' 和'a-z'是沒有區別的。此標記僅作用於TestString和CondPattern的比較, 而對文件系統和子請求的測試不起作用。
'ornext|OR' (or next condition)
它以OR方式組合若干規則的條件,而不是隱含的AND。典型的例子如下:
RewriteCond %{REMOTE_HOST}  ^host1.*  
RewriteCond %{REMOTE_HOST}  ^host2.*  
RewriteCond %{REMOTE_HOST}  ^host3.*
RewriteRule ...some special stuff for any of these hosts...

如果不用這個標記,則必須使用三個 條件/規則。
舉例:

如果要按請求頭中的``User-Agent:'重寫一個站點的主頁,可以這樣寫:

RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
RewriteRule  ^/$                 /homepage.max.html  

RewriteCond  %{HTTP_USER_AGENT}  ^Lynx.*
RewriteRule  ^/$                 /homepage.min.html  

RewriteRule  ^/$                 /homepage.std.html  

含義: 如果你使用的瀏覽器是Netscape Navigator(其識別標誌是'Mozilla'), 則你將得到內容最大化的主頁,包括Frames等等; 如果你使用的是(基於終端的)Lynx,則你得到的是內容最小化的主頁,不包含tables等等; 如果你使用的是其他的瀏覽器,則你得到的是一個標準的主頁。


RewriteEngine 指令

RewriteEngine指令打開或關閉運行時刻的重寫引擎。 如果設置為off,則mod_rewrite模塊不執行任何運行時刻的重寫操作, 甚至也不更新SCRIPT_URx環境變數。

使用該指令可以使mod_rewrite模塊無效,而無須註釋所有的RewriteRule指令!

注意:默認情況下,重寫配置是不可繼承的, 即,必須在每個需要的虛擬主機中設置一個RewriteEngine on指令。


RewriteLock 指令

此指令設置mod_rewrite為了和RewriteMap 程序通訊而使用的一個同步加鎖文件的名稱。 在需要使用重寫映射表程序時,它必須是一個本地路徑(而不能是一個NFS掛接設備); 對其他類型的重寫映射表,則無此要求。


RewriteLog 指令

RewriteLog指令設置用於記錄所有重寫操作的文件的名稱。 如果此文件名不是以斜杠('/')開頭,則它是相對於Server Root的。 此指令應該僅僅出現在伺服器級配置中。

如果要關閉對重寫操作的記錄,不推薦把Filename設置為/dev/null, 因為,雖然重寫引擎不能輸出記錄了,但仍會內部地建立這個日誌文件, 它會使伺服器速度降低,而且對管理員毫無益處! 要關閉日誌,可以刪除或註解RewriteLog指令, 或者使用RewriteLogLevel 0!
安全
參見Apache Security Tips,其中講述了, 為什麼如果存放日誌的目錄對除了啟動伺服器以外的用戶是可寫的會帶來安全隱患。
舉例
RewriteLog "/usr/local/var/apache/logs/rewrite.log"


RewriteLogLevel 指令

RewriteLogLevel指令設置重寫引擎日誌的詳細程度的級別。 默認級別0意味著不記錄,而9或更大的值意味著記錄所有的操作。

要關閉重寫引擎日誌,可以簡單地設此值為0,關閉所有的重寫操作記錄。

使用較高的Level值會使Apache伺服器速度急劇下降! 重寫日誌使用大於2的Level值只用於調試!
舉例
RewriteLogLevel 3


RewriteMap 指令

RewriteMap定義一個映射表, 由映射函數用於查找關鍵詞來插入/替換欄位。此查找操作的源可以是多種類型。

MapName是映射表的名稱, 指定了一個映射函數,用於重寫規則的字元串替換,它可以是下列形式之一:

${ MapName : LookupKey }
${ MapName : LookupKey | DefaultValue }

如果使用了這樣的形式,則會在MapName中查找關鍵詞LookupKey。 如果找到了,則被替換成SubstValue; 如果沒有找到,則被替換成DefaultValue, 如果沒有指定DefaultValue,則被替換成空字元串。

可以使用下列MapType和MapSource的組合:

標準純文本
MapType: txt, MapSource: 有效的Unix文件系統文件名
這是重寫映射表的標準形式,即, MapSource是一個純文本文件,包含空行、註釋行(以字元'#'打頭), 以及每行一個的替換對,如下。

MatchingKey SubstValue

Example
##
##  map.txt -- rewriting map
##

Ralf.S.Engelschall    rse   # Bastard Operator From Hell
Mr.Joe.Average        joe   # Mr. Average

RewriteMap real-to-user txt:/path/to/file/map.txt

隨機純文本
MapType: rnd, MapSource: 有效的Unix文件系統文件名
這個與上述的標準純文本很相似,但它有一個特殊的后處理特性: 查找完畢后,會解析其中包含的含義為``or''和``|''符號。 也就是說,會隨機地選擇其中之一作為實際的返回值。 雖然這看似毫無意義,但它的設計意圖是, 在一個查找值是伺服器名稱的反向代理環境中,實現負載平衡。如:

##
##  map.txt -- rewriting map
##

static   www1|www2|www3|www4
dynamic  www5|www6

RewriteMap servers rnd:/path/to/file/map.txt

散列文件
MapType: dbm[=type], MapSource: 有效的Unix文件系統文件名
這裡的源是一個二進位格式的DBM文件,包含了與純文本相同的內容, 但是因為它有優化的特殊表現形式,使它的查找速度明顯快得多。 此類型可以是sdbm, gdbm, ndbm或db,由compile-time settings所決定。如果省略type,則使用編譯時選擇的預設設置。 你可以使用任何DBM工具或者下列Perl腳本來建立這個文件,但必須保證DBM的類型正確。 建立NDBM文件的例子:

#!/path/to/bin/perl
##
##  txt2dbm -- convert txt map to dbm format
##

use NDBM_File;
use Fcntl;

($txtmap, $dbmmap) = @ARGV;

open(TXT, "<$txtmap") or die "Couldn't open $txtmap!\n";
tie (%DB, 'NDBM_File', $dbmmap,O_RDWR|O_TRUNC|O_CREAT, 0644)
   or die "Couldn't create $dbmmap!\n";

while (<TXT>;) {
   next if (/^\s*#/ or /^\s*$/);
   $DB{$1} = $2 if (/^\s*(\S+)\s+(\S+)/);
}

untie %DB;
close(TXT);

$ txt2dbm map.txt map.db

內部函數
MapType: int, MapSource: 內部的Apache函數
這裡的源是一個內部的Apache函數。 目前,還不能由你自己建立,只能使用下列已經存在的函數:

toupper:
轉換查找關鍵詞為大寫.
tolower:
轉換查找關鍵詞為小寫.
escape:
轉換查找關鍵詞中的特殊字元為十六進位編碼.
unescape:
轉換查找關鍵詞中的十六進位編碼為特殊字元.
外部的重寫程序
MapType: prg, MapSource: 有效的Unix文件系統文件名
這裡的源是一個程序,而不是一個映射表文件。 程序的編製語言可以隨意選擇,但最終結果必須是可執行的 (即, 或者是目標代碼,或者是首行為'#!/path/to/interpreter'的腳本).

此程序僅在Apache伺服器啟動時啟動一次, 隨後通過stdin和stdout文件句柄與重寫引擎交互。 對每個映射函數的查找操作,它從stdin接收以回車結束的查找關鍵詞, 然後把查找結果以回車結束反饋到stdout, 如果查找失敗,則返回四個字元的``NULL'' (即, 對給定的關鍵詞沒有對應的值)。 此程序的最簡單形式是一個1:1的映射(即,key == value),如:

#!/usr/bin/perl
$| = 1;
while (<STDIN>;) {
     # ...put here any transformations or lookups...
     print $_;
}

但是必須注意:

``即使它看來簡單而愚蠢,只要正確,就保持原樣(Keep it simple, stupid)'' (KISS), 因為,在規則起作用時,此程序的崩潰會直接導致Apache伺服器的崩潰。
避免犯一個常見的錯誤: 絕不要對stdout做緩衝I/O! 它會導致死循環! 所以上述例子中才會有``$|=1''...
使用RewriteLock指令定義一個加鎖文件, 用於同步mod_rewrite和此程序之間的通訊。預設時是沒有同步操作的。
RewriteMap指令允許多次出現。 對每個映射函數都可以使用一個RewriteMap指令來定義其重寫映射表。 雖然不能在目錄的上下文中定義映射表, 但是,完全可以在其中使用映射表。

注意
對於純文本和DBM格式的文件,已經查找過的關鍵詞會被緩存在內核中, 直到映射表的mtime改變了或者伺服器重啟了。 這樣,你可以把每個請求都會用到的映射函數放在規則中,這是沒有問題的,因為外部查找只進行一次!

RewriteOptions 指令

RewriteOptions指令為當前伺服器級和目錄級的配置設置一些選項。 Option可以是下列值之一:

inherit
此值強制當前配置可以繼承其父配置。 在虛擬主機級配置中,它意味著主伺服器的映射表、條件和規則可以被繼承。 在目錄級配置中,它意味著其父目錄的.htaccess中的條件和規則可以被繼承。
MaxRedirects=number
為了避免目錄級RewriteRule的無休止的內部重定向, 在此類重定向和500內部伺服器錯誤次數達到一個最大值的時候, mod_rewrite會停止對此請求的處理。 如果你確實需要對每個請求允許大於10次的內部重定向,可以增大這個值。

RewriteRule 指令

RewriteRule指令是重寫引擎的根本。此指令可以多次使用。 每個指令定義一個簡單的重寫規則。這些規則的定義順序尤為重要, 因為,在運行時刻,規則是按這個順序逐一生效的.

Pattern是一個作用於當前URL的兼容perl的正則表達式. 這裡的``當前''是指該規則生效時的URL的值。 它可能與被請求的URL不同,因為其他規則可能在此之前已經發生匹配並對它做了改動。

正則表達式的一些用法:

Text:
   .           Any single character
        Character class: One  of chars
   [^chars]    Character class: None of chars
   text1|text2 Alternative: text1 or text2

Quantifiers:
   ?           0 or 1 of the preceding text
   *           0 or N of the preceding text (N >; 0)
   +           1 or N of the preceding text (N >; 1)

Grouping:
   (text)      Grouping of text
               (either to set the borders of an alternative or
               for making backreferences where the Nth group can
               be used on the RHS of a RewriteRule with $N)

Anchors:
   ^           Start of line anchor
   $           End   of line anchor

Escaping:
   \char       escape that particular char
               (for instance to specify the chars ".[]()" etc.)

更多有關正則表達式的資料請參見perl正則表達式手冊頁("perldoc perlre"). 如果你對正則表達式的更詳細的資料及其變種(POSIX regex 等.)感興趣, 請參見以下專著:

Mastering Regular Expressions
Jeffrey E.F. Friedl
Nutshell Handbook Series
O'Reilly & Associates, Inc. 1997
ISBN 1-56592-257-3


另外,在mod_rewrite中,還可以使用否字元('!')的pattern前綴,以實現pattern的反轉。 比如:``如果當前URL不與pattern相匹配''. 它用於使用否pattern較容易描述的需要排除的某些情況,或者作為最後一條規則。

注意
使用否字元以反轉pattern時,pattern中不能使用分組的通配成分。 由於pattern不匹配而使分組的內容是空的,所以它是不可能實現的。 因此,如果使用了否pattern,那麼後繼的字元串中就不能使用$N!
重寫規則中的Substitution是, 當原始URL與Pattern相匹配時,用以替代(或替換)的字元串。 除了純文本,還可以使用

$N 反向引用RewriteRule的pattern
%N 反向引用最後匹配的RewriteCond pattern
規則條件測試字元串中(%{VARNAME})的伺服器變數
映射函數調用(${mapname:key|default})
反向引用的$N (N=0..9) 是指用Pattern所匹配的第N組的內容去替換URL。 伺服器變數與RewriteCond指令的TestString相同。 映射函數由RewriteMap指令所決定,其說明也參見該指令。 這三種類型變數按上面列表中的順序被擴展。

如上所述,所有的重寫規則都是(按配置文件中的定義順序)作用於Substitution的。 URL被Substitution完全地替換,並繼續處理直到所有規則處理完畢, 除非用L標記顯式地終結 - 見下文。

'-'是一個特殊的替換串,意思是不要替換! 似乎很愚蠢吧? 不, 它可以用於僅僅匹配某些URL而無須替換的情況下,即, 在發生替換前,允許以C (chain)標記連接的多個pattern同時起作用。

還有,你甚至可以在替換字元串中新建包含請求串的URL。 在替換串中使用問號,以標明其後繼的成分應該被重新注入到QUERY_STRING中。 要刪除一個已有的請求串,可以用問號來終結替換字元串。

注意
一個特殊功能: 在用http://thishost[]作為替換欄位的前綴時, mod_rewrite會把它自動剝離出去。 在配合生成主機名的映射函數使用的時候, 這個對隱含的外部重定向URL的精簡化操作是有用的而且是重要的。 下面例子一節中的第一個例子有助於理解這點。
謹記
由於此功能的存在,以http://thishost為前綴的無條件外部重定向在你自己的伺服器上是無效的。 要做這樣一個自身的重定向,必須使用R標記 (見下文).
此外,Substitution還可以追加特殊標記



作為RewriteRule指令的第三個參數。 Flags是一個包含以逗號分隔的下列標記的列表:

'redirect|R [=code]' (強制重定向 redirect)
以http://thishost[]/(使新的URL成為一個URI) 為前綴的Substitution可以強制性執行一個外部重定向。 如果code沒有指定,則產生一個HTTP響應代碼302(臨時性移動)。 如果需要使用在300-400範圍內的其他響應代碼,只需在此指定這個數值即可, 另外,還可以使用下列符號名稱之一: temp (默認的), permanent, seeother. 用它可以把規範化的URL反饋給客戶端,如, 重寫``/~''為 ``/u/'',或對/u/user加上斜杠,等等。

注意: 在使用這個標記時,必須確保該替換欄位是一個有效的URL! 否則,它會指向一個無效的位置! 並且要記住,此標記本身只是對URL加上 http://thishost[]/的前綴,重寫操作仍然會繼續。 通常,你會希望停止重寫操作而立即重定向,則還需要使用'L'標記.

'forbidden|F' (強制URL為被禁止的 forbidden)
強制當前URL為被禁止的,即,立即反饋一個HTTP響應代碼403(被禁止的)。 使用這個標記,可以鏈接若干RewriteConds以有條件地阻塞某些URL。
'gone|G' (強制URL為已廢棄的 gone)
強制當前URL為已廢棄的,即,立即反饋一個HTTP響應代碼410(已廢棄的)。 使用這個標記,可以標明頁面已經被廢棄而不存在了.
'proxy|P' (強製為代理 proxy)
此標記使替換成分被內部地強製為代理請求,並立即(即, 重寫規則處理立即中斷)把處理移交給代理模塊。 你必須確保此替換串是一個有效的(比如常見的以 http://hostname開頭的)能夠為Apache代理模塊所處理的URI。 使用這個標記,可以把某些遠程成分映射到本地伺服器名稱空間, 從而增強了ProxyPass指令的功能。
注意: 要使用這個功能,代理模塊必須編譯在Apache伺服器中。 如果你不能確定,可以檢查``httpd -l''的輸出中是否有mod_proxy.c。 如果有,則mod_rewrite可以使用這個功能; 如果沒有,則必須啟用mod_proxy並重新編譯``httpd''程序。

'last|L' (最後一個規則 last)
立即停止重寫操作,並不再應用其他重寫規則。 它對應於Perl中的last命令或C語言中的break命令。 這個標記可以阻止當前已被重寫的URL為其後繼的規則所重寫。 舉例,使用它可以重寫根路徑的URL('/')為實際存在的URL, 比如, '/e/www/'.
'next|N' (重新執行 next round)
重新執行重寫操作(從第一個規則重新開始). 這時再次進行處理的URL已經不是原始的URL了,而是經最後一個重寫規則處理的URL。 它對應於Perl中的next命令或C語言中的continue命令。 此標記可以重新開始重寫操作,即, 立即回到循環的頭部。
但是要小心,不要製造死循環!
'chain|C' (與下一個規則相鏈接 chained)
此標記使當前規則與下一個(其本身又可以與其後繼規則相鏈接的, 並可以如此反覆的)規則相鏈接。 它產生這樣一個效果: 如果一個規則被匹配,通常會繼續處理其後繼規則, 即,這個標記不起作用;如果規則不能被匹配, 則其後繼的鏈接的規則會被忽略。比如,在執行一個外部重定向時, 對一個目錄級規則集,你可能需要刪除``.www'' (此處不應該出現``.www''的)。
'type|T=MIME-type' (強制MIME類型 type)
強制目標文件的MIME類型為MIME-type。 比如,它可以用於模擬mod_alias中的ScriptAlias指令, 以內部地強制被映射目錄中的所有文件的MIME類型為``application/x-httpd-cgi''.
'nosubreq|NS' (僅用於不對內部子請求進行處理 no internal sub-request)
在當前請求是一個內部子請求時,此標記強制重寫引擎跳過該重寫規則。 比如,在mod_include試圖搜索可能的目錄默認文件(index.xxx)時, Apache會內部地產生子請求。對子請求,它不一定有用的,而且如果整個規則集都起作用, 它甚至可能會引發錯誤。所以,可以用這個標記來排除某些規則。

根據你的需要遵循以下原則: 如果你使用了有CGI腳本的URL前綴,以強制它們由CGI腳本處理, 而對子請求處理的出錯率(或者開銷)很高,在這種情況下,可以使用這個標記。

'nocase|NC' (忽略大小寫 no case)
它使Pattern忽略大小寫,即, 在Pattern與當前URL匹配時,'A-Z' 和'a-z'沒有區別。
'qsappend|QSA' (追加請求串 query string append)
此標記強制重寫引擎在已有的替換串中追加一個請求串,而不是簡單的替換。 如果需要通過重寫規則在請求串中增加信息,就可以使用這個標記。
'noescape|NE' (在輸出中不對URI作轉義 no URI escaping)
此標記阻止mod_rewrite對重寫結果應用常規的URI轉義規則。 一般情況下,特殊字元(如'%', '$', ';'等)會被轉義為等值的十六進位編碼。 此標記可以阻止這樣的轉義,以允許百分號等符號出現在輸出中,如:
RewriteRule /foo/(.*) /bar?arg=P1\%3d$1

可以使'/foo/zed'轉向到一個安全的請求'/bar?arg=P1=zed'.
'passthrough|PT' (移交給下一個處理器 pass through)
此標記強制重寫引擎將內部結構request_rec中的uri欄位設置為 filename欄位的值,它只是一個小修改,使之能對來自其他URI到文件名翻譯器的 Alias,ScriptAlias, Redirect 等指令的輸出進行後續處理。舉一個能說明其含義的例子: 如果要通過mod_rewrite的重寫引擎重寫/abc為/def, 然後通過mod_alias使/def轉變為/ghi,可以這樣:
RewriteRule ^/abc(.*) /def$1
Alias /def /ghi

如果省略了PT標記,雖然mod_rewrite運作正常, 即, 作為一個使用API的URI到文件名翻譯器, 它可以重寫uri=/abc/...為filename=/def/..., 但是,後續的mod_alias在試圖作URI到文件名的翻譯時,則會失效。
注意: 如果需要混合使用不同的包含URI到文件名翻譯器的模塊時, 就必須使用這個標記。。 混合使用mod_alias和mod_rewrite就是個典型的例子。

For Apache hackers
如果當前Apache API除了URI到文件名hook之外,還有一個文件名到文件名的hook, 就不需要這個標記了! 但是,如果沒有這樣一個hook,則此標記是唯一的解決方案。 Apache Group討論過這個問題,並在Apache 2.0 版本中會增加這樣一個hook。
'skip|S=num' (跳過後繼的規則 skip)
此標記強制重寫引擎跳過當前匹配規則後繼的num個規則。 它可以實現一個偽if-then-else的構造: 最後一個規則是then從句,而被跳過的skip=N個規則是else從句. (它和'chain|C'標記是不同的!)
'env|E=VAR:VAL' (設置環境變數 environment variable)
此標記使環境變數VAR的值為VAL, VAL可以包含可擴展的反向引用的正則表達式$N和%N。 此標記可以多次使用以設置多個變數。 這些變數可以在其後許多情況下被間接引用,但通常是在XSSI (via <!--#echo var="VAR"-->;) or CGI (如 $ENV{'VAR'})中, 也可以在後繼的RewriteCond指令的pattern中通過%{ENV:VAR}作引用。 使用它可以從URL中剝離並記住一些信息。
'cookie|CO=NAME:VAL:domain[:lifetime[]]' (設置cookie)
它在客戶端瀏覽器上設置一個cookie。 cookie的名稱是NAME,其值是VAL。 domain欄位是該cookie的域,比如'.apache.org', 可選的lifetime是cookie生命期的分鐘數, 可選的path是cookie的路徑。
注意
絕不要忘記,在伺服器級配置文件中,Pattern是作用於整個URL的。 但是在目錄級配置文件中, (一般總是和特定目錄名稱相同的)目錄前綴會在pattern匹配時被自動刪除, 而又在替換完畢后自動被加上。此特性對很多種重寫是必須的,因為, 如果沒有這個剝離前綴的動作,就必須與其父目錄去匹配,而這並不總是可行的。
但是有一個例外: 如果替換串以``http://''開頭, 則不會附加目錄前綴, 而是強制產生一個外部重定向,或者(如果使用了P標記)是一個代理操作!

注意
為了對目錄級配置啟用重寫引擎,你必須在這些文件中設置``RewriteEngine On'', 並且打開``Options FollowSymLinks'。 如果管理員對用戶目錄禁用了FollowSymLinks, 則無法使用重寫引擎。這個限制是為了安全而設置的。
以下是所有可能的替換組合及其含義:

在伺服器級配置中(httpd.conf)
,對這樣一個請求 ``GET /somepath/pathinfo'':


Given Rule                                      Resulting Substitution
----------------------------------------------  ----------------------------------
^/somepath(.*) otherpath$1                      not supported, because invalid!

^/somepath(.*) otherpath$1                   not supported, because invalid!

^/somepath(.*) otherpath$1                   not supported, because invalid!
----------------------------------------------  ----------------------------------
^/somepath(.*) /otherpath$1                     /otherpath/pathinfo

^/somepath(.*) /otherpath$1                  http://thishost/otherpath/pathinfo
                                                 via external redirection

^/somepath(.*) /otherpath$1                  not supported, because silly!
----------------------------------------------  ----------------------------------
^/somepath(.*) http://thishost/otherpath$1      /otherpath/pathinfo

^/somepath(.*) http://thishost/otherpath$1   http://thishost/otherpath/pathinfo
                                                 via external redirection

^/somepath(.*) http://thishost/otherpath$1   not supported, because silly!
----------------------------------------------  ----------------------------------
^/somepath(.*) http://otherhost/otherpath$1     http://otherhost/otherpath/pathinfo
                                                 via external redirection

^/somepath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo
                                                 via external redirection
                                                 (the flag is redundant)

^/somepath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo
                                                 via internal proxy

在/somepath的目錄級配置中
(即, 目錄/physical/path/to/somepath的.htaccess文件中包含 RewriteBase /somepath)
對這樣一個請求``GET /somepath/localpath/pathinfo'':


Given Rule                                      Resulting Substitution
----------------------------------------------  ----------------------------------
^localpath(.*) otherpath$1                      /somepath/otherpath/pathinfo

^localpath(.*) otherpath$1                   http://thishost/somepath/otherpath/pathinfo
                                                 via external redirection

^localpath(.*) otherpath$1                   not supported, because silly!
----------------------------------------------  ----------------------------------
^localpath(.*) /otherpath$1                     /otherpath/pathinfo

^localpath(.*) /otherpath$1                  http://thishost/otherpath/pathinfo
                                                 via external redirection

^localpath(.*) /otherpath$1                  not supported, because silly!
----------------------------------------------  ----------------------------------
^localpath(.*) http://thishost/otherpath$1      /otherpath/pathinfo

^localpath(.*) http://thishost/otherpath$1   http://thishost/otherpath/pathinfo
                                                 via external redirection

^localpath(.*) http://thishost/otherpath$1   not supported, because silly!
----------------------------------------------  ----------------------------------
^localpath(.*) http://otherhost/otherpath$1     http://otherhost/otherpath/pathinfo
                                                 via external redirection

^localpath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo
                                                 via external redirection
                                                 (the flag is redundant)

^localpath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo
                                                 via internal proxy

舉例:

要重寫這種形式的URL

/ Language /~ Realname /.../ File



/u/ Username /.../ File . Language

可以把這樣的對應關係保存在/path/to/file/map.txt映射文件中, 此後,只要在Apache伺服器配置文件中增加下列行,即可:

RewriteLog   /path/to/file/rewrite.log
RewriteMap   real-to-user               txt:/path/to/file/map.txt
RewriteRule  ^/([^/]+)/~([^/]+)/(.*)$   /u/${real-to-user:$2|nobody}/$3.$1

[ 本帖最後由 HonestQiao 於 2006-10-26 11:56 編輯 ]
《解決方案》

mod_rewrite 詳解

高手呀
《解決方案》

mod_rewrite 詳解

有沒mod_vhost_alias的詳解?
《解決方案》

mod_rewrite 詳解

高手!高手!高手!我已經擺好供品,上好香,頂禮膜拜! :em11:
《解決方案》

mod_rewrite 詳解

不錯呀!看來要好好學習了!我一直解決不了這個問題的!
《解決方案》

一個rewrite的問題!

在httpd.conf 怎麼才能把:http://www.abc.com  重新定向到http://momo.bokee.com/harir/index.home 這個地址。
《解決方案》

求小橋再編輯一下帖子 把那些表情去掉吧 我列印收藏呢
《解決方案》

原帖由 zoudeshun666 於 2006-10-25 11:29 發表
在httpd.conf 怎麼才能把:http://www.abc.com  重新定向到http://momo.bokee.com/harir/index.home 這個地址。

用redirect重定向嘍.
refresh 也可以.

conf中好像不能做吧。
《解決方案》

說了半天,沒看到基本的配置怎麼做
《解決方案》

原帖由 taoxc 於 2007-1-11 11:31 發表
說了半天,沒看到基本的配置怎麼做

現在看手冊就可以了:
http://man.chinaunix.net/newsoft/ApacheMenual_CN_2.2new/rewrite/index.html

[火星人 ] mod_rewrite 詳解已經有691次圍觀

http://coctec.com/docs/service/show-post-41419.html