Apache模塊 mod_rewrite
說明 | 一個基于一定規(guī)則的實時重寫URL請求的引擎 |
---|---|
狀態(tài) | 擴(kuò)展(E) |
模塊名 | rewrite_module |
源文件 | mod_rewrite.c |
兼容性 | 僅在 Apache 1.3 及以后的版本中可用 |
概述
此模塊提供了一個基于正則表達(dá)式分析器的重寫引擎來實時重寫URL請求。它支持每個完整規(guī)則可以擁有不限數(shù)量的子規(guī)則以及附加條件規(guī)則 的靈活而且強(qiáng)大的URL操作機(jī)制。此URL操作可以依賴于各種測試,比如服務(wù)器變量、環(huán)境變量、HTTP頭、時間標(biāo)記,甚至各種格式的用于匹配URL組成 部分的查找數(shù)據(jù)庫。
此模塊可以操作URL的所有部分(包括路徑信息部分),在服務(wù)器級的(httpd.conf
)和目錄級的(.htaccess
)配置都有效,還可以生成最終請求字符串。此重寫操作的結(jié)果可以是內(nèi)部子處理,也可以是外部請求的轉(zhuǎn)向,甚至還可以是內(nèi)部代理處理。
但是,所有這些功能和靈活性帶來一個問題,那就是復(fù)雜性,因此,不要指望一天之內(nèi)就能看懂整個模塊。
更多的討論、細(xì)節(jié)、示例,請查看詳細(xì)的URL重寫文檔。
特殊字符的引用
在Apache 1.3.20中,TestString和Substitution中的特殊字符可以用前導(dǎo)斜杠(\)來實現(xiàn)轉(zhuǎn)義(即忽略其特殊含義而視之為普通字符)。 比如,Substitution可以用"\$
"來包含一個美元符號,以避免mod_rewrite把它視為反向引用。
環(huán)境變量
此模塊會跟蹤兩個額外的(非標(biāo)準(zhǔn))CGI/SSI環(huán)境變量,SCRIPT_URL
和SCRIPT_URI
。他們包含了當(dāng)前資源的邏輯網(wǎng)絡(luò)視圖,而標(biāo)準(zhǔn)CGI/SSI變量SCRIPT_NAME
和SCRIPT_FILENAME
包含的是物理系統(tǒng)視圖。
注意:這些變量保持的是其最初被請求時的URI/URL,即在任何重寫操作之前的URI/URL。其重要性在于他們是重寫操作重寫URL到物理路徑名的原始依據(jù)。
示例
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/
RewriteBase 指令
說明 | 設(shè)置目錄級重寫的基準(zhǔn)URL |
---|---|
語法 |
RewriteBase URL-path
|
默認(rèn)值 |
參見使用方法
|
作用域 | directory, .htaccess |
覆蓋項 | FileInfo |
狀態(tài) | 擴(kuò)展(E) |
模塊 | mod_rewrite |
RewriteBase
指令顯式地設(shè)置了目錄級重寫的基準(zhǔn)URL。在下文中,你將看到RewriteBase
physical-directory-path"。
在對一個新的URL進(jìn)行替換時,此模塊必須把這個URL重新注入到服務(wù)器處理中。為此,它必須知道其對應(yīng)的URL前綴或者說URL基準(zhǔn)。通常,此前綴就是對應(yīng)的文件路徑。但是,大多數(shù)網(wǎng)站URL不是直接對應(yīng)于其物理文件路徑的,因而一般不能做這樣的假定! 所以在這種情況下,就必須用RewriteBase
指令來指定正確的URL前綴。
例如,目錄級配置文件內(nèi)容如下:
# /abc/def/.htaccess -- /abc/def 目錄的配置文件
# 注意:/abc/def 是 /xyz 的物理路徑(例如存在一條'Alias /xyz /abc/def'指令)。
RewriteEngine On
# 讓服務(wù)器知道我們使用的是 /xyz 而不是物理路徑 /abc/def
RewriteBase /xyz
# 重寫規(guī)則
RewriteRule ^oldstuff\.html$ newstuff.html
上述例子中,對/xyz/oldstuff.html
的請求被正確地重寫為對物理文件/abc/def/newstuff.html
的請求。
僅供Apache Hacker們參考
以下列出了內(nèi)部處理的詳細(xì)步驟:
請求:
/xyz/oldstuff.html
內(nèi)部處理過程:
/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)
結(jié)果:
/abc/def/newstuff.html
雖然這個過程看來很繁復(fù),但是由于目錄級重寫的到來時機(jī)已經(jīng)太晚了,它不得不把這個(重寫)請求重新注入到 Apache核心中,所以Apache內(nèi)部確實是這樣處理的。但是:它的開銷并不象看起來的那樣大,因為重新注入完全在Apache服務(wù)器內(nèi)部進(jìn)行,而且 這樣的過程在Apache內(nèi)部也為其他許多操作所使用。所以,你可以充分信任其設(shè)計和實現(xiàn)是正確的。
RewriteCond 指令
說明 | 定義重寫發(fā)生的條件 |
---|---|
語法 |
RewriteCond TestStringCondPattern [flags]
|
作用域 | server config, virtual host, directory, .htaccess |
覆蓋項 | FileInfo |
狀態(tài) | 擴(kuò)展(E) |
模塊 | mod_rewrite |
RewriteCond
指令定義了規(guī)則生效的條件,即在一個RewriteRule
指令之前可以有一個或多個RewriteCond
指令。條件之后的重寫規(guī)則僅在當(dāng)前URI與Pattern匹配并且滿足此處的條件(TestString能夠與CondPattern匹配)時才會起作用。
TestString是一個純文本的字符串,但是還可以包含下列可擴(kuò)展的成分:
-
RewriteRule反向引用 ,引用方法是:
(0 <= N <= 9)引用當(dāng)前(帶有若干$N
RewriteRule
指令的)RewriteCond
中的與Pattern匹配的分組成分(圓括號!)。 -
RewriteCond反向引用 ,引用方法是:
(1 <= N <= 9)引用當(dāng)前若干%N
RewriteCond
條件中最后符合的條件中的分組成分(圓括號!)。 -
RewriteMap擴(kuò)展 ,引用方法是:
細(xì)節(jié)請參見RewriteMap 指令。${mapname:key|default}
-
服務(wù)器變量 ,引用方法是:
NAME_OF_VARIABLE可以是下表列出的字符串之一:%{
NAME_OF_VARIABLE}
HTTP頭 連接與請求 HTTP_USER_AGENT
HTTP_REFERER
HTTP_COOKIE
HTTP_FORWARDED
HTTP_HOST
HTTP_PROXY_CONNECTION
HTTP_ACCEPTREMOTE_ADDR
REMOTE_HOST
REMOTE_PORT
REMOTE_USER
REMOTE_IDENT
REQUEST_METHOD
SCRIPT_FILENAME
PATH_INFO
QUERY_STRING
AUTH_TYPE服務(wù)器自身 日期和時間 其它 DOCUMENT_ROOT
SERVER_ADMIN
SERVER_NAME
SERVER_ADDR
SERVER_PORT
SERVER_PROTOCOL
SERVER_SOFTWARETIME_YEAR
TIME_MON
TIME_DAY
TIME_HOUR
TIME_MIN
TIME_SEC
TIME_WDAY
TIMEAPI_VERSION
THE_REQUEST
REQUEST_URI
REQUEST_FILENAME
IS_SUBREQ
HTTPS這些變量都對應(yīng)于類似命名的HTTP MIME頭、Apache服務(wù)器的C變量、Unix系統(tǒng)中的
struct tm
字段,其中的大多數(shù)在其他的手冊或者CGI規(guī)范中都有說明。 其中為mod_rewrite所特有的變量如下:IS_SUBREQ
- 如果正在處理的請求是一個子請求,它將包含字符串"true",否則就是"false"。模塊為了解析URI中的附加文件,可能會產(chǎn)生子請求。
API_VERSION
- 這是正在使用中的Apache模塊API(服務(wù)器和模塊之間內(nèi)部接口)的版本, 其定義位于include/ap_mmn.h中。此模塊API版本對應(yīng)于正在使用的Apache的版本(比如在Apache 1.3.14的發(fā)行版中這個值是19990320:10)。 通常,對它感興趣的是模塊的開發(fā)者。
THE_REQUEST
- 這是由瀏覽器發(fā)送的完整的HTTP請求行(比如:"
GET /index.html HTTP/1.1
")。它不包含任何瀏覽器發(fā)送的其它頭信息。 REQUEST_URI
- 這是在HTTP請求行中所請求的資源(比如上述例子中的"/index.html")。
REQUEST_FILENAME
- 這是與請求相匹配的完整的本地文件系統(tǒng)的文件路徑名。
HTTPS
- 如果連接使用了SSL/TLS,它將包含字符串"on",否則就是"off"(無論
mod_ssl
是否已經(jīng)加載,該變量都可以安全的使用)。
其它注意事項:
- SCRIPT_FILENAME和REQUEST_FILENAME包含的值是相同的——即Apache服務(wù)器內(nèi)部的
request_rec
結(jié)構(gòu)中的filename
字段。 第一個就是大家都知道的CGI變量名,而第二個則是REQUEST_URI(request_rec
結(jié)構(gòu)中的uri
字段)的一個副本。 - 特殊形式:
%{ENV:variable}
,其中的variable可以是任意環(huán)境變量。它是通過查找Apache內(nèi)部結(jié)構(gòu)或者(如果沒找到的話)由Apache服務(wù)器進(jìn)程通過getenv()
得到的。 - 特殊形式:
%{SSL:variable}
,其中的variable可以是一個SSL環(huán)境變量的名字,無論mod_ssl
模塊是否已經(jīng)加載都可以使用(未加載時為空字符串)。比如:%{SSL:SSL_CIPHER_USEKEYSIZE}
將會被替換為128
。 - 特殊形式:
%{HTTP:header}
,其中的header可以是任意HTTP MIME頭的名稱。它總是可以通過查找HTTP請求而得到。比如:%{HTTP:Proxy-Connection}
將被替換為Proxy-Connection:
HTTP頭的值。 - 預(yù)設(shè)形式:
%{LA-U:variable}
,variable的最終值在執(zhí)行一個內(nèi)部(基于URL的)子請求后確定。 當(dāng)需要使用一個目前未知但是會在之后的過程中設(shè)置的變量的時候,就可以使用這個方法。例如,需要在服務(wù)器級配置(
httpd.conf
文件)中根據(jù)REMOTE_USER
變量進(jìn)行重寫, 就必須使用%{LA-U:REMOTE_USER}
。因為此變量是由URL重寫(mod_rewrite)步驟之后的認(rèn)證步驟設(shè)置的。 但是另一方面,因為mod_rewrite是通過API修正步驟來實現(xiàn)目錄級(.htaccess
文件)配置的, 而認(rèn)證步驟先于API修正步驟,所以可以用%{REMOTE_USER}
。 - 預(yù)設(shè)形式:
%{LA-F:variable}
,variable的最終值在執(zhí)行一個內(nèi)部(基于文件名的)子請求后確定。 大多數(shù)情況下和上述的LA-U是相同的。
CondPattern是條件模式,即一個應(yīng)用于當(dāng)前TestString實例的正則表達(dá)式。TestString將被首先計算,然后再與CondPattern匹配。
注意: CondPattern是一個perl兼容的正則表達(dá)式,但是還有若干增補(bǔ):
- 可以在CondPattern串的開頭使用'
!
'(驚嘆號)來指定不匹配。 -
CondPatterns有若干特殊的變種。除了正則表達(dá)式的標(biāo)準(zhǔn)用法,還有下列用法:
- '<CondPattern'(詞典順序的小于)
將CondPattern視為純字符串,與TestString按詞典順序進(jìn)行比較。如果TestString小于CondPattern則為真。 - '>CondPattern'(詞典順序的大于)
將CondPattern視為純字符串,與TestString按詞典順序進(jìn)行比較。如果TestString大于CondPattern則為真。 - '=CondPattern'(詞典順序的等于)
將CondPattern視為純字符串,與TestString按詞典順序進(jìn)行比較。如果TestString等于CondPattern(兩個字符串逐個字符地完全相等)則為真。如果CondPattern是""
(兩個雙引號),則TestString將與空字符串進(jìn)行比較。 - '-d'(目錄)
將TestString視為一個路徑名并測試它是否為一個存在的目錄。 - '-f'(常規(guī)文件)
將TestString視為一個路徑名并測試它是否為一個存在的常規(guī)文件。 - '-s'(非空的常規(guī)文件)
將TestString視為一個路徑名并測試它是否為一個存在的、尺寸大于0的常規(guī)文件。 - '-l'(符號連接)
將TestString視為一個路徑名并測試它是否為一個存在的符號連接。 - '-x'(可執(zhí)行)
將TestString視為一個路徑名并測試它是否為一個存在的、具有可執(zhí)行權(quán)限的文件。該權(quán)限由操作系統(tǒng)檢測。 - '-F'(對子請求存在的文件)
檢查TestString是否為一個有效的文件,而且可以在服務(wù)器當(dāng)前的訪問控制配置下被訪問。它使用一個內(nèi)部子請求來做檢查,由于會降低服務(wù)器的性能,所以請謹(jǐn)慎使用! - '-U'(對子請求存在的URL)
檢查TestString是否為一個有效的URL,而且可以在服務(wù)器當(dāng)前的訪問控制配置下被訪問。它使用一個內(nèi)部子請求來做檢查,由于會降低服務(wù)器的性能,所以請謹(jǐn)慎使用!
注意
所有這些測試都可以用驚嘆號作前綴('!')以實現(xiàn)測試條件的反轉(zhuǎn)。 - '<CondPattern'(詞典順序的小于)
- 還可以在CondPattern之后追加特殊的標(biāo)記
[flags]
作為RewriteCond
指令的第三個參數(shù)。flags是一個以逗號分隔的以下標(biāo)記的列表:- '
nocase|NC
'(忽略大小寫)
它使測試忽略大小寫,擴(kuò)展后的TestString和CondPattern中'A-Z' 和'a-z'是沒有區(qū)別的。此標(biāo)記僅用于TestString和CondPattern的比較,而對文件系統(tǒng)和子請求的檢查不起作用。 - '
ornext|OR
'(或下一條件)
它以O(shè)R方式組合若干規(guī)則的條件,而不是隱含的AND。典型的例子如下:如果不用這個標(biāo)記,你就必須要書寫三次條件/規(guī)則對。RewriteCond %{REMOTE_HOST} ^host1.* [OR]
RewriteCond %{REMOTE_HOST} ^host2.* [OR]
RewriteCond %{REMOTE_HOST} ^host3.*
RewriteRule ... 針對這3個主機(jī)的規(guī)則集 ...
- '
舉例
如果要按請求頭中的"User-Agent:
"重寫一個站點的主頁,可以這樣寫:
RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*
RewriteRule ^/$ /homepage.max.html [L]
RewriteCond %{HTTP_USER_AGENT} ^Lynx.*
RewriteRule ^/$ /homepage.min.html [L]
RewriteRule ^/$ /homepage.std.html [L]
解釋:如果你使用的瀏覽器識別標(biāo)志是'Mozilla',則你將得到內(nèi)容最大化的主頁(含有Frames等等)。如果你使用的是 (基于終端的)Lynx,則你得到的是內(nèi)容最小化的主頁(不含table等等)。如果上述條件都不滿足(使用的是其他瀏覽器),則你得到的是一個標(biāo)準(zhǔn)的主 頁。
RewriteEngine 指令
說明 | 打開或關(guān)閉運行時的重寫引擎 |
---|---|
語法 |
RewriteEngine on|off
|
默認(rèn)值 |
RewriteEngine off
|
作用域 | server config, virtual host, directory, .htaccess |
覆蓋項 | FileInfo |
狀態(tài) | 擴(kuò)展(E) |
模塊 | mod_rewrite |
RewriteEngine
指令打開或關(guān)閉運行時的重寫引擎。如果設(shè)置為off
,則此模塊在運行時不執(zhí)行任何重寫操作, 同時也不更新SCRIPT_URx
環(huán)境變量。
使用該指令可以使此模塊無效,而無須注釋所有的RewriteRule
指令!
注意:默認(rèn)情況下,重寫配置是不可繼承的,也就是必須在每個需要使用重寫引擎的虛擬主機(jī)中設(shè)置一個RewriteEngine on
指令。
RewriteLock 指令
說明 | 設(shè)置RewriteMap 同步所使用的鎖文件名 |
---|---|
語法 |
RewriteLock file-path
|
作用域 | server config |
狀態(tài) | 擴(kuò)展(E) |
模塊 | mod_rewrite |
此指令設(shè)置mod_rewrite為了和RewriteMap
程序通訊而使用的同步鎖文件的名稱。 在需要使用重寫映射表程序(rewriting map-program)時,它必須是一個本地路徑(而不能是一個NFS掛接設(shè)備)。對其他類型的重寫映射表(rewriting map),則無此要求。
RewriteLog 指令
說明 | 設(shè)置重寫引擎日志的文件名 |
---|---|
語法 |
RewriteLog file-path
|
作用域 | server config, virtual host |
狀態(tài) | 擴(kuò)展(E) |
模塊 | mod_rewrite |
RewriteLog
指令設(shè)置用于記錄所有重寫操作的日志文件的名稱。如果此文件名不以斜杠('/
')開頭,則它是相對于Server Root的,此指令應(yīng)該在每個服務(wù)器級別的配置中僅僅出現(xiàn)一次。
/dev/null
,因為,雖然重寫引擎不能輸出記錄了,但仍會在內(nèi)部建立這個日志文件,這樣會使服務(wù)器速度降低,而且對管理員毫無益處!要關(guān)閉日志,可以刪除或注解RewriteLog
指令, 或者使用"RewriteLogLevel 0
"的設(shè)置安全
參見安全方面的提示文檔,其中講述了為什么如果存放日志的目錄對除了啟動服務(wù)器以外的用戶是可寫的會帶來安全隱患。示例
RewriteLog "/usr/local/var/apache/logs/rewrite.log"
RewriteLogLevel 指令
說明 | 設(shè)置重寫日志的詳細(xì)程度 |
---|---|
語法 |
RewriteLogLevel Level
|
默認(rèn)值 |
RewriteLogLevel 0
|
作用域 | server config, virtual host |
狀態(tài) | 擴(kuò)展(E) |
模塊 | mod_rewrite |
RewriteLogLevel
指令設(shè)置重寫引擎日志的詳細(xì)程度的級別。0(默認(rèn)級別)意味著不記錄,而9或更大的值意味著記錄所有操作。
要關(guān)閉重寫引擎日志,可以簡單地將Level設(shè)為0,以關(guān)閉所有重寫操作的記錄。
示例
RewriteLogLevel 3
RewriteMap 指令
說明 | 定義用于關(guān)鍵詞查找的映射函數(shù) |
---|---|
語法 |
RewriteMap MapNameMapType:MapSource
|
作用域 | server config, virtual host |
狀態(tài) | 擴(kuò)展(E) |
模塊 | mod_rewrite |
兼容性 | Apache 2.0.41 及以后的版本中可以使用不同的dbm類型 |
RewriteMap
指令定義了一個映射表(Rewriting Map),映射函數(shù)將使用該表來查找關(guān)鍵字然后插入/替換字段。此查找操作的源可以是多種類型。
MapName 是映射表的名稱,指定了一個映射函數(shù),用于重寫規(guī)則的字符串替換,它可以是下列形式之一:
${
MapName
:
LookupKey
}
${
MapName
:
LookupKey
|
DefaultValue
}
如果使用了這樣的形式,則會在MapName中查找關(guān)鍵詞LookupKey。如果找到了,則被替換成SubstValue; 如果沒有找到,則被替換成DefaultValue,如果沒有指定DefaultValue,則被替換成空字符串。
例如,你可能定義這樣一個RewriteMap
:
RewriteMap examplemap txt:/path/to/file/map.txt
然后你就可以像下面這樣在RewriteRule
中使用該映射:
RewriteRule ^/ex/(.*) ${examplemap:$1}
可以使用下列MapType和MapSource的組合:
-
標(biāo)準(zhǔn)純文本
MapType:txt
, MapSource: 有效的Unix文件系統(tǒng)文件名這是重寫映射表的標(biāo)準(zhǔn)形式。MapSource是一個純文本文件,包含空行、注釋行(以字符'#'打頭),以及每行一個的替換對,如下所示:
MatchingKeySubstValue
例子
## map.txt -- rewriting map
Ralf.S.Engelschall rse # Bastard Operator From Hell
Mr.Joe.Average joe # Mr. AverageRewriteMap real-to-user txt:/path/to/file/map.txt
-
隨機(jī)純文本
MapType:rnd
, MapSource: 有效的Unix文件系統(tǒng)文件名這個與上述的標(biāo)準(zhǔn)純文本很相似,但它有一個特殊的后處理特性:查找完畢后,會解析其中包含的"
|
"符號(含義為"或")。 也就是說,會隨機(jī)地選擇其中之一作為返回值。雖然這看似毫無意義,但設(shè)計它的意圖是在一個查找值是服務(wù)器名稱的反向代理環(huán)境中實現(xiàn)負(fù)載平衡。例子
映射文件
## map.txt -- rewriting map
static www1|www2|www3|www4
dynamic www5|www6配置指令
RewriteMap servers rnd:/path/to/file/map.txt
RewriteRule ^/(.*\.(png|gif|jpg)) http://${servers:static}/$1 [NC,P,L]
RewriteRule ^/(.*) http://${servers:dynamic}/$1 [P,L] -
散列文件
MapType:dbm[=type]
, MapSource: 有效的Unix文件系統(tǒng)文件名這里的源是一個二進(jìn)制格式的DBM文件,包含了與純文本相同的內(nèi)容,但是因為它有優(yōu)化了的特殊表現(xiàn)形式,使它的查找速度明顯快得多。 此type可以是sdbm, gdbm, ndbm, db(由編譯時配置決定)。如果省略type,則使用編譯時選擇的缺省值。 你可以使用任何DBM工具或者下列Perl腳本來創(chuàng)建這個文件,但必須保證DBM的類型正確。建立NDBM文件的例子如下:
#!/path/to/bin/perl
##
## txt2dbm -- 將 txt 映射表轉(zhuǎn)換為 dbm 格式
##
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
-
內(nèi)部函數(shù)
MapType:int
, MapSource: Apache內(nèi)部函數(shù)這里的源是一個Apache的內(nèi)部函數(shù)。目前,還不能由你自己建立,只能使用下列已經(jīng)存在的函數(shù):
- toupper:
轉(zhuǎn)換查找關(guān)鍵詞為大寫 - tolower:
轉(zhuǎn)換查找關(guān)鍵詞為小寫 - escape:
轉(zhuǎn)換查找關(guān)鍵詞中的特殊字符為十六進(jìn)制編碼 - unescape:
轉(zhuǎn)換查找關(guān)鍵詞中的十六進(jìn)制編碼為特殊字符
- toupper:
-
外部的重寫程序
MapType:prg
, MapSource: 有效的Unix文件系統(tǒng)文件名這里的源是一個程序,而不是一個映射表文件。程序設(shè)計語言可以隨意選擇,但最終結(jié)果必須是可執(zhí)行的(或者是目標(biāo)代碼,或者是首行為'
#!/path/to/interpreter
'的腳本)。此程序僅在Apache服務(wù)器啟動時啟動一次,隨后通過
stdin
和stdout
文件句柄與重寫引擎交互。 對每個映射函數(shù)的查找操作,它從stdin
接收以回車結(jié)束的查找關(guān)鍵詞,然后把查找的結(jié)果以回車結(jié)束反饋到stdout
,如果查找失敗,則返回四個字符的字符串"NULL"(對給定的關(guān)鍵詞沒有對應(yīng)的值)。此程序的最簡單形式是一個1:1的映射(即:key == value),例如:#!/usr/bin/perl
$| = 1;
while (<STDIN>) {
# ...在這里放置轉(zhuǎn)換和查找...
print $_;
}但是必須注意:
- "簡單就是美"(KISS: Keep it simple, stupid!)。此程序的崩潰會直接導(dǎo)致Apache服務(wù)器的崩潰。
- 絕不要對
stdout
做I/O緩沖(一個常見的錯誤),它會導(dǎo)致死循環(huán)!所以上述例子中才會使用"$|=1
"來預(yù)防。 - 使用
RewriteLock
指令定義一個鎖文件,用于同步mod_rewrite和此程序之間的通訊。默認(rèn)是沒有同步操作的。
RewriteMap
指令可以多次出現(xiàn)。對每個映射函數(shù)都可以使用一個RewriteMap
指令來定義其重寫映射表。雖然不能在目錄上下文(per-directory context)中定義映射表,但是完全可以在其中使用映射表。
注意
對于純文本和DBM格式的文件,已經(jīng)查找過的關(guān)鍵詞會被緩存在內(nèi)核中,直到映射表的mtime
改變了或者服務(wù)器重啟了。這樣,你可以把每個請求都會用到的映射函數(shù)放在規(guī)則中,這是沒有問題的,因為外部查找只進(jìn)行一次。
RewriteOptions 指令
說明 | 為重寫引擎設(shè)置一些特殊的選項 |
---|---|
語法 |
RewriteOptions Options
|
作用域 | server config, virtual host, directory, .htaccess |
覆蓋項 | FileInfo |
狀態(tài) | 擴(kuò)展(E) |
模塊 | mod_rewrite |
兼容性 |
MaxRedirects 在2.1及以后的版本中已經(jīng)不可用 |
RewriteOptions
指令為當(dāng)前服務(wù)器級和目錄級的配置設(shè)置一些選項。Option當(dāng)前僅可以是如下值:
-
inherit
- 此值強(qiáng)制當(dāng)前配置繼承其父配置。在虛擬主機(jī)級配置中,它意味著主服務(wù)器的映射表、條件和規(guī)則可以被繼承。在目錄級配置中,它意味著其父目錄的
.htaccess
中的條件和規(guī)則可以被繼承。
RewriteRule 指令
說明 | 為重寫引擎定義重寫規(guī)則 |
---|---|
語法 |
RewriteRule PatternSubstitution [flags]
|
作用域 | server config, virtual host, directory, .htaccess |
覆蓋項 | FileInfo |
狀態(tài) | 擴(kuò)展(E) |
模塊 | mod_rewrite |
兼容性 | cookie-flag在Apache 2.0.40及以后的版本中可用 |
RewriteRule
指令是重寫引擎的根本。此指令可以多次使用。每個指令定義一個簡單的重寫規(guī)則。這些規(guī)則的定義順序尤為重要——在運行時,規(guī)則是按這個順序逐一生效的。
Pattern 是一個作用于當(dāng)前URL的perl兼容的正則表達(dá)式。"當(dāng)前URL"是指該規(guī)則生效時刻的URL的值。它可能與被請求的URL截然不同,因為其他規(guī)則可能在此之前已經(jīng)發(fā)生匹配并對它做了改動。
正則表達(dá)式的一些用法示例:
文本
.
任意一個單字符[
chars]
字符類: "chars"中的任意一個字符[^
chars]
字符類: 不在"chars"中的字符
text1|
text2 選擇: text1 或 text2
量詞?
前面的字符出現(xiàn) 0 或 1 次*
前面的字符出現(xiàn) 0 或 N 次(N > 0)+
前面的字符出現(xiàn) 1 或 N 次(N > 1)
分組(
text)
text 組
(常用于設(shè)置一個選擇的邊界,或用于生成后引用:
在RewriteRule中可以用$
N 引用第N個分組)
錨^
錨定到行首$
錨定到行尾
轉(zhuǎn)義\
c 對給定的字符c進(jìn)行轉(zhuǎn)義
(比如對".[]()
"進(jìn)行轉(zhuǎn)義,等等)
更多有關(guān)正則表達(dá)式的資料請參見perl正則表達(dá)式手冊頁("perldoc perlre")。另外,在mod_rewrite中,還可以使用否字符('!
')前綴實現(xiàn)反轉(zhuǎn)。比如:"如果當(dāng)前URL不與模式相匹配"它用于使用否定式匹配模式較容易描述的某些情況,或者作為最后一條規(guī)則。
注意
使用否字符以反轉(zhuǎn)匹配模式時,匹配模式中不能使用分組的通配成分。由于模式不匹配而使分組的內(nèi)容是空的,所以它是不可能實現(xiàn)的。 因此,如果使用了否定式匹配模式,那么后繼的字符串中就不能使用$N
重寫規(guī)則中的Substitution是當(dāng)原始URL與Pattern相匹配時,用來替代(或替換)的字符串。除了純文本,還可以包含:
- 對Pattern的反向引用(
$N
) - 對最后匹配的RewriteCond的反向引用(
%N
) - 規(guī)則條件測試字符串(
%{VARNAME}
)中的服務(wù)器變量 -
映射函數(shù)調(diào)用(
${mapname:key|default}
)
反向引用的$
N(N=0..9)是指用Pattern匹配的第N組的內(nèi)容去替換URL。服務(wù)器變量與RewriteCond
指令的TestString相同。映射函數(shù)由RewriteMap
指令決定,其說明也參見該指令。這三種類型變量按上面列表中的順序被展開。
如上所述,所有的重寫規(guī)則都是按配置文件中的定義順序作用于Substitution的。URL被Substitution完全替換,并繼續(xù)處理直到所有規(guī)則處理完畢,除非用L
標(biāo)記顯式地終結(jié)(見下文)。
'-
'是一個特殊的替換串,意思是不替換。它可以用于僅僅匹配某些URL而無須替換的情況,比如,在發(fā)生替換前,允許以C(chain)標(biāo)記連接的多個匹配模式同時起作用。
此外,在Substitution之后還可以追加[
flags]
標(biāo)記作為RewriteRule
指令的第三個參數(shù)。Flags是一個包含以逗號分隔的下列標(biāo)記的列表:
- '
chain|C
'(鏈接下一規(guī)則)
此標(biāo)記使當(dāng)前規(guī)則與下一個規(guī)則相鏈接。它產(chǎn)生這樣的效果:如果一個規(guī)則被匹配,則繼續(xù)處理其后繼規(guī)則,也就是這個標(biāo)記不起作用;如果該規(guī)則不被匹配,則其后繼規(guī)則將被跳過。比如,在一個目錄級規(guī)則中執(zhí)行一個外部重定向時,你可能需要刪除".www
"(此處不應(yīng)該出現(xiàn)".www
")。 - '
cookie|CO=
NAME:VAL:domain[:lifetime[:path]]'(設(shè)置cookie)
在客戶端設(shè)置一個cookie。cookie的名稱是NAME,值是VAL。domain是該cookie的域,比如'.apache.org',可選的lifetime是cookie的有效期(分鐘),可選的path是cookie的路徑。 - '
env|E=
VAR:VAL'(設(shè)置環(huán)境變量)
此標(biāo)記將環(huán)境變量VAR的值為VAL,VAL可以包含可擴(kuò)展的正則表達(dá)式反向引用($N
和%N
)。此標(biāo)記可以多次使用以設(shè)置多個變量。這些變量可以在其后許多情況下被間接引用,通常是在XSSI(<!--#echo var="VAR"-->
)或CGI($ENV{'VAR'}
)中,也可以在后繼的RewriteCond
指令的CondPattern參數(shù)中通過%{ENV:VAR}
引用。使用它可以記住從URL中剝離的信息。 - '
forbidden|F
'(強(qiáng)制禁止URL)
強(qiáng)制禁止當(dāng)前URL,也就是立即反饋一個HTTP響應(yīng)碼403(被禁止的)。使用這個標(biāo)記,可以鏈接若干個RewriteConds來有條件地阻塞某些URL。 - '
gone|G
'(強(qiáng)制廢棄URL)
強(qiáng)制當(dāng)前URL為已廢棄,也就是立即反饋一個HTTP響應(yīng)碼410(已廢棄的)。使用這個標(biāo)記,可以標(biāo)明頁面已經(jīng)被廢棄而不存在了。 - '
handler|H
=Content-handler'(強(qiáng)制指定內(nèi)容處理器)
強(qiáng)自制定目標(biāo)文件的內(nèi)容處理器為Content-handler。例如,用來模擬mod_alias
模塊的- '
last|L
'(結(jié)尾規(guī)則)
立即停止重寫操作,并不再應(yīng)用其他重寫規(guī)則。它對應(yīng)于Perl中的last
命令或C語言中的break
命令。這個標(biāo)記用于阻止當(dāng)前已被重寫的URL被后繼規(guī)則再次重寫。例如,使用它可以重寫根路徑的URL('/
')為實際存在的URL(比如:'/e/www/
')。- '
next|N
'(從頭再來)
重新執(zhí)行重寫操作(從第一個規(guī)則重新開始)。此時再次進(jìn)行處理的URL已經(jīng)不是原始的URL了,而是經(jīng)最后一個重寫規(guī)則處理過的URL。它對應(yīng)于Perl中的next
命令或C語言中的continue
命令。此標(biāo)記可以重新開始重寫操作(立即回到循環(huán)的開頭)。但是要小心,不要制造死循環(huán)!- '
nocase|NC
'(忽略大小寫)
它使Pattern忽略大小寫,也就是在Pattern與當(dāng)前URL匹配時,'A-Z'和'a-z'沒有區(qū)別。- '
noescape|NE
'(在輸出中不對URI進(jìn)行轉(zhuǎn)義)
此標(biāo)記阻止mod_rewrite對重寫結(jié)果應(yīng)用常規(guī)的URI轉(zhuǎn)義規(guī)則。 一般情況下,特殊字符('%', '$', ';'等)會被轉(zhuǎn)義為等值的十六進(jìn)制編碼('%25', '%24', '%3B'等)。此標(biāo)記可以阻止這樣的轉(zhuǎn)義,以允許百分號等符號出現(xiàn)在輸出中,比如:可以使'RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE]
/foo/zed
轉(zhuǎn)向到一個安全的請求'/bar?arg=P1=zed
'。- '
nosubreq|NS
'(不對內(nèi)部子請求進(jìn)行處理)
在當(dāng)前請求是一個內(nèi)部子請求時,此標(biāo)記強(qiáng)制重寫引擎跳過該重寫規(guī)則。比如,在mod_include
試圖搜索目錄默認(rèn)文件(index.xxx
)時,Apache會在內(nèi)部產(chǎn)生子請求。對于子請求,重寫規(guī)則不一定有用,而且如果整個規(guī)則集都起作用,它甚至可能會引發(fā)錯誤。所以,可以用這個標(biāo)記來排除某些規(guī)則。
使用原則:如果你為URL添加了CGI腳本前綴,以強(qiáng)制它們由CGI腳本處理,但對子請求處理的出錯率(或者資源開銷)很高,在這種情況下,可以使用這個標(biāo)記。- '
proxy|P
'(強(qiáng)制為代理)
此標(biāo)記使替換成分被內(nèi)部地強(qiáng)制作為代理請求發(fā)送,并立即中斷重寫處理,然后把處理移交給mod_proxy模塊。你必須確保此替換串是一個能夠被mod_proxy處理的有效URI(比如以http://
hostname開頭),否則將得到一個代理模塊返回的錯誤。使用這個標(biāo)記,可以把某些遠(yuǎn)程成分映射到本地服務(wù)器域名空間,從而增強(qiáng)了ProxyPass指令的功能。注意:要使用這個功能,必須已經(jīng)啟用了
mod_proxy
模塊。- '
passthrough|PT
'(移交給下一個處理器)
此標(biāo)記強(qiáng)制重寫引擎將內(nèi)部request_rec
結(jié)構(gòu)中的uri
字段設(shè)置為filename
字段的值,這個小小的修改使得RewriteRule
指令的輸出能夠被(從URI轉(zhuǎn)換到文件名的)Alias
,ScriptAlias
,Redirect
等指令進(jìn)行后續(xù)處理[原文:This flag is just a hack to enable post-processing of the output ofRewriteRule
directives, usingAlias
,ScriptAlias
,Redirect
, and other directives from various URI-to-filename translators.]。舉一個能說明其含義的例子: 如果要將/abc
重寫為/def
, 然后再使用mod_alias
將/def
轉(zhuǎn)換為/ghi
,可以這樣:如果省略了RewriteRule ^/abc(.*) /def$1 [PT]
Alias /def /ghiPT
標(biāo)記,雖然將uri=/abc/...
重寫為filename=/def/...
的部分運作正常,但是后續(xù)的mod_alias
在試圖將URI轉(zhuǎn)換到文件名時會遭遇失效。注意:如果需要混合使用多個將URI轉(zhuǎn)換到文件名的模塊時,就必須使用這個標(biāo)記。。此處混合使用
mod_alias
和mod_rewrite
就是個典型的例子。- '
qsappend|QSA
'(追加查詢字符串)
此標(biāo)記強(qiáng)制重寫引擎在已有的替換字符串中追加一個查詢字符串,而不是簡單的替換。如果需要通過重寫規(guī)則在請求串中增加信息,就可以使用這個標(biāo)記。- '
redirect|R
[=code]'(強(qiáng)制重定向)
若Substitution以http://thishost[:thisport]/
(使新的URL成為一個URI)開頭,可以強(qiáng)制性執(zhí)行一個外部重定向。如果沒有指定code,則產(chǎn)生一個HTTP響應(yīng)碼302(臨時性移動)。如果需要使用在300-400范圍內(nèi)的其他響應(yīng)代碼,只需在此指定即可(或使用下列符號名稱之一:temp
(默認(rèn)),permanent
,seeother
)。使用它可以把規(guī)范化的URL反饋給客戶端,如將"/~
"重寫為"/u/
",或始終對/u/
user加上斜杠,等等。
注意:在使用這個標(biāo)記時,必須確保該替換字段是一個有效的URL。否則,它會指向一個無效的位置!并且要記住,此標(biāo)記本身只是對URL加上http://thishost[:thisport]/
前綴,重寫操作仍然會繼續(xù)進(jìn)行。通常,你還會希望停止重寫操作而立即重定向,那么就還需要使用'L'標(biāo)記。- '
skip|S
=num'(跳過后繼規(guī)則)
此標(biāo)記強(qiáng)制重寫引擎跳過當(dāng)前匹配規(guī)則之后的num個規(guī)則。它可以模擬if-then-else結(jié)構(gòu):最后一個規(guī)則是then從句,而被跳過的skip=N
個規(guī)則是else從句。注意:它和'chain|C'標(biāo)記是不同的!- '
type|T
=MIME-type'(強(qiáng)制MIME類型)
強(qiáng)制目標(biāo)文件的MIME類型為MIME-type,可以用來基于某些特定條件強(qiáng)制設(shè)置內(nèi)容類型。比如,下面的指令可以讓.php
文件在以.phps
擴(kuò)展名調(diào)用的情況下由mod_php
按照PHP源代碼的MIME類型(application/x-httpd-php-source)顯示:RewriteRule ^(.+\.php)s$ $1 [T=application/x-httpd-php-source]
- '
目錄級重寫
為了在RewriteEngine On"和"Options FollowSymLinks
"。如果管理員禁止了該目錄的FollowSymLinks
特性,重寫引擎將不會工作,這樣做的原因是處于安全方面的考慮。
在服務(wù)器級配置中,模式匹配是作用于整個URL的。但是在目錄級配置文件.htaccess
中使用重寫引擎的時候,目錄前綴(一般總是和特定的目錄名稱相同)將會在模式匹配前被自動移除并在替換完成后被自動添加回去。這個特性對于重寫來說是非常重要的,否則你就被迫必須總是對父目錄進(jìn)行匹配,而這并不總是可行的。這里有一個例外:如果替換字符串以"http://
"開頭,則不會添加目錄前綴,而是強(qiáng)制執(zhí)行一個外部重定向或代理操作(如果使用了P標(biāo)志的話)。參見RewriteBase
指令以獲得更多信息。
還可以在<Directory>
配置段中使用重寫引擎,前綴匹配規(guī)則與在.htaccess
中使用重寫引擎時完全相同,并且這種做法更加簡單。然而,為了避免前綴替換復(fù)雜化,我們還是建議盡量將重寫規(guī)則放置在主服務(wù)器或虛擬主機(jī)配置部分,而不是放置在<Directory>
配置段中。
雖然重寫規(guī)則在語法上允許放置在<Location>
配置段中,但這不是必須的,并且我們也反對這樣做。
注意:絕對URL的替換
當(dāng)替換字段以"http://thishost[:thisport]
"作為前綴時,mod_rewrite
會將它自動剝離出去。在配合生成主機(jī)名部分的映射函數(shù)使用的時候,這個對隱含的外部重定向URL的簡化操作是有用的而且是重要的。下面的第一個例子有助于理解這點。
謹(jǐn)記:由于此功能的存在,以"http://thishost
"為前綴的無條件外部重定向到自身所在的服務(wù)器是無效的。要實現(xiàn)一個到自身的重定向,必須使用R標(biāo)記。
注意:查詢字符串
Pattern不會按照查詢字符串進(jìn)行匹配。為了達(dá)到這個目的,你必須使用一個帶有%{QUERY_STRING}
變量的RewriteCond
指令。當(dāng)然,你也可以在替換字符串中創(chuàng)建包含查詢字符串的URL:在替換字符串串中使用問號,以標(biāo)明其后的部分應(yīng)該被重新注入到QUERY_STRING中。而要刪除一個已有的請求串,則可以用問號來終結(jié)替換字符串。為了聯(lián)合新舊查詢字符串,請使用[QSA]
標(biāo)志。
以下是所有可能的替換組合及其含義:
在服務(wù)器級配置中(httpd.conf
)
對給定的請求"GET /somepath/pathinfo
":
給定的規(guī)則 得到的替換字符串
---------------------------------------------- ----------------------------------
^/somepath(.*) otherpath$1 非法,不被支持
^/somepath(.*) otherpath$1 [R] 非法,不被支持
^/somepath(.*) otherpath$1 [P] 非法,不被支持
---------------------------------------------- ----------------------------------
^/somepath(.*) /otherpath$1 /otherpath/pathinfo
^/somepath(.*) /otherpath$1 [R] http://thishost/otherpath/pathinfo
通過外部重定向
^/somepath(.*) /otherpath$1 [P] 毫無意義,不被支持
---------------------------------------------- ----------------------------------
^/somepath(.*) http://thishost/otherpath$1 /otherpath/pathinfo
^/somepath(.*) http://thishost/otherpath$1 [R] http://thishost/otherpath/pathinfo
通過外部重定向
^/somepath(.*) http://thishost/otherpath$1 [P] 毫無意義,不被支持
---------------------------------------------- ----------------------------------
^/somepath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo
通過外部重定向
^/somepath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo
通過外部重定向
([R]標(biāo)記是多余的)
^/somepath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo
通過內(nèi)部代理
在/somepath
的目錄級配置中
(也就是/physical/path/to/somepath/.htacccess
文件中含有:RewriteBase /somepath
)
對給定的請求"GET /somepath/localpath/pathinfo
":
給定的規(guī)則 得到的替換字符串
---------------------------------------------- ----------------------------------
^localpath(.*) otherpath$1 /somepath/otherpath/pathinfo
^localpath(.*) otherpath$1 [R] http://thishost/somepath/otherpath/pathinfo
通過外部重定向
^localpath(.*) otherpath$1 [P] 毫無意義,不被支持
---------------------------------------------- ----------------------------------
^localpath(.*) /otherpath$1 /otherpath/pathinfo
^localpath(.*) /otherpath$1 [R] http://thishost/otherpath/pathinfo
通過外部重定向
^localpath(.*) /otherpath$1 [P] 毫無意義,不被支持
---------------------------------------------- ----------------------------------
^localpath(.*) http://thishost/otherpath$1 /otherpath/pathinfo
^localpath(.*) http://thishost/otherpath$1 [R] http://thishost/otherpath/pathinfo
通過外部重定向
^localpath(.*) http://thishost/otherpath$1 [P] 毫無意義,不被支持
---------------------------------------------- ----------------------------------
^localpath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo
通過外部重定向
^localpath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo
通過外部重定向
([R]標(biāo)記是多余的)
^localpath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo
通過內(nèi)部代理