Apache模塊 mod_rewrite
說明
|
一個(gè)基于一定規(guī)則的實(shí)時(shí)重寫URL請求的引擎 |
狀態(tài)
|
擴(kuò)展(E) |
模塊名
|
rewrite_module |
源文件
|
mod_rewrite.c |
兼容性
|
僅在 Apache 1.3 及以后的版本中可用 |
概述
此模塊提供了一個(gè)基于正則表達(dá)式分析器的重寫引擎來實(shí)時(shí)重寫URL請求。它支持每個(gè)完整規(guī)則可以擁有不限數(shù)量的子規(guī)則以及附加條件規(guī)則
的靈活而且強(qiáng)大的URL操作機(jī)制。此URL操作可以依賴于各種測試,比如服務(wù)器變量、環(huán)境變量、HTTP頭、時(shí)間標(biāo)記,甚至各種格式的用于匹配URL組成
部分的查找數(shù)據(jù)庫。
此模塊可以操作URL的所有部分(包括路徑信息部分),在服務(wù)器級的(httpd.conf
)和目錄級的(.htaccess
)配置都有效,還可以生成最終請求字符串。此重寫操作的結(jié)果可以是內(nèi)部子處理,也可以是外部請求的轉(zhuǎn)向,甚至還可以是內(nèi)部代理處理。
但是,所有這些功能和靈活性帶來一個(gè)問題,那就是復(fù)雜性,因此,不要指望一天之內(nèi)就能看懂整個(gè)模塊。
更多的討論、細(xì)節(jié)、示例,請查看詳細(xì)的URL重寫文檔。
在Apache 1.3.20中,TestString和Substitution中的特殊字符可以用前導(dǎo)斜杠(\)來實(shí)現(xiàn)轉(zhuǎn)義(即忽略其特殊含義而視之為普通字符)。 比如,Substitution可以用"\$
"來包含一個(gè)美元符號,以避免mod_rewrite把它視為反向引用。
此模塊會跟蹤兩個(gè)額外的(非標(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)視圖。
注意:這些變量保持的是其最初被請求時(shí)的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
physical-directory-path"。
在對一個(gè)新的URL進(jìn)行替換時(shí),此模塊必須把這個(gè)URL重新注入到服務(wù)器處理中。為此,它必須知道其對應(yīng)的URL前綴或者說URL基準(zhǔn)。通常,此前綴就是對應(yīng)的文件路徑。但是,大多數(shù)網(wǎng)站URL不是直接對應(yīng)于其物理文件路徑的,因而一般不能做這樣的假定! 所以在這種情況下,就必須用RewriteBase
指令來指定正確的URL前綴。
如果你的網(wǎng)站服務(wù)器URL
不是與物理文件路徑直接對應(yīng)的,你必須在每個(gè)使用
RewriteRule
的
.htaccess
文件中使用
RewriteBase
指令。
例如,目錄級配置文件內(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
雖然這個(gè)過程看來很繁復(fù),但是由于目錄級重寫的到來時(shí)機(jī)已經(jīng)太晚了,它不得不把這個(gè)(重寫)請求重新注入到
Apache核心中,所以Apache內(nèi)部確實(shí)是這樣處理的。但是:它的開銷并不象看起來的那樣大,因?yàn)橹匦伦⑷胪耆贏pache服務(wù)器內(nèi)部進(jìn)行,而且
這樣的過程在Apache內(nèi)部也為其他許多操作所使用。所以,你可以充分信任其設(shè)計(jì)和實(shí)現(xiàn)是正確的。
說明
|
定義重寫發(fā)生的條件 |
語法
|
RewriteCond TestStringCondPattern [flags]
|
作用域
|
server config, virtual host, directory, .htaccess |
覆蓋項(xiàng)
|
FileInfo |
狀態(tài)
|
擴(kuò)展(E) |
模塊
|
mod_rewrite |
RewriteCond
指令定義了規(guī)則生效的條件,即在一個(gè)RewriteRule
指令之前可以有一個(gè)或多個(gè)RewriteCond
指令。條件之后的重寫規(guī)則僅在當(dāng)前URI與Pattern匹配并且滿足此處的條件(TestString能夠與CondPattern匹配)時(shí)才會起作用。
TestString是一個(gè)純文本的字符串,但是還可以包含下列可擴(kuò)展的成分:
其它注意事項(xiàng):
- SCRIPT_FILENAME和REQUEST_FILENAME包含的值是相同的——即Apache服務(wù)器內(nèi)部的
request_rec
結(jié)構(gòu)中的filename
字段。 第一個(gè)就是大家都知道的CGI變量名,而第二個(gè)則是REQUEST_URI(request_rec
結(jié)構(gòu)中的uri
字段)的一個(gè)副本。
- 特殊形式:
%{ENV:variable}
,其中的variable可以是任意環(huán)境變量。它是通過查找Apache內(nèi)部結(jié)構(gòu)或者(如果沒找到的話)由Apache服務(wù)器進(jìn)程通過getenv()
得到的。
- 特殊形式:
%{SSL:variable}
,其中的variable可以是一個(gè)SSL環(huán)境變量的名字,無論mod_ssl
模塊是否已經(jīng)加載都可以使用(未加載時(shí)為空字符串)。比如:%{SSL:SSL_CIPHER_USEKEYSIZE}
將會被替換為128
。
- 特殊形式:
%{HTTP:header}
,其中的header可以是任意HTTP MIME頭的名稱。它總是可以通過查找HTTP請求而得到。比如:%{HTTP:Proxy-Connection}
將被替換為Proxy-Connection:
HTTP頭的值。
- 預(yù)設(shè)形式:
%{LA-U:variable}
,variable的最終值在執(zhí)行一個(gè)內(nèi)部(基于URL的)子請求后確定。 當(dāng)需要使用一個(gè)目前未知但是會在之后的過程中設(shè)置的變量的時(shí)候,就可以使用這個(gè)方法。
例如,需要在服務(wù)器級配置(httpd.conf
文件)中根據(jù)REMOTE_USER
變量進(jìn)行重寫, 就必須使用%{LA-U:REMOTE_USER}
。因?yàn)榇俗兞渴怯蒛RL重寫(mod_rewrite)步驟之后的認(rèn)證步驟設(shè)置的。 但是另一方面,因?yàn)閙od_rewrite是通過API修正步驟來實(shí)現(xiàn)目錄級(.htaccess
文件)配置的, 而認(rèn)證步驟先于API修正步驟,所以可以用%{REMOTE_USER}
。
- 預(yù)設(shè)形式:
%{LA-F:variable}
,variable的最終值在執(zhí)行一個(gè)內(nèi)部(基于文件名的)子請求后確定。 大多數(shù)情況下和上述的LA-U是相同的。
CondPattern是條件模式,即一個(gè)應(yīng)用于當(dāng)前TestString實(shí)例的正則表達(dá)式。TestString將被首先計(jì)算,然后再與CondPattern匹配。
注意:
CondPattern是一個(gè)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(兩個(gè)字符串逐個(gè)字符地完全相等)則為真。如果CondPattern是""
(兩個(gè)雙引號),則TestString將與空字符串進(jìn)行比較。 - '-d'(目錄)
將TestString視為一個(gè)路徑名并測試它是否為一個(gè)存在的目錄。 - '-f'(常規(guī)文件)
將TestString視為一個(gè)路徑名并測試它是否為一個(gè)存在的常規(guī)文件。 - '-s'(非空的常規(guī)文件)
將TestString視為一個(gè)路徑名并測試它是否為一個(gè)存在的、尺寸大于0的常規(guī)文件。 - '-l'(符號連接)
將TestString視為一個(gè)路徑名并測試它是否為一個(gè)存在的符號連接。 - '-x'(可執(zhí)行)
將TestString視為一個(gè)路徑名并測試它是否為一個(gè)存在的、具有可執(zhí)行權(quán)限的文件。該權(quán)限由操作系統(tǒng)檢測。 - '-F'(對子請求存在的文件)
檢查TestString是否為一個(gè)有效的文件,而且可以在服務(wù)器當(dāng)前的訪問控制配置下被訪問。它使用一個(gè)內(nèi)部子請求來做檢查,由于會降低服務(wù)器的性能,所以請謹(jǐn)慎使用! - '-U'(對子請求存在的URL)
檢查TestString是否為一個(gè)有效的URL,而且可以在服務(wù)器當(dāng)前的訪問控制配置下被訪問。它使用一個(gè)內(nèi)部子請求來做檢查,由于會降低服務(wù)器的性能,所以請謹(jǐn)慎使用!
注意
所有這些測試都可以用驚嘆號作前綴('!')以實(shí)現(xiàn)測試條件的反轉(zhuǎn)。
- 還可以在CondPattern之后追加特殊的標(biāo)記
[flags]
作為RewriteCond
指令的第三個(gè)參數(shù)。flags是一個(gè)以逗號分隔的以下標(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。典型的例子如下:
RewriteCond %{REMOTE_HOST} ^host1.* [OR]
RewriteCond %{REMOTE_HOST} ^host2.* [OR]
RewriteCond %{REMOTE_HOST} ^host3.*
RewriteRule ... 針對這3個(gè)主機(jī)的規(guī)則集 ...
如果不用這個(gè)標(biāo)記,你就必須要書寫三次條件/規(guī)則對。
舉例
如果要按請求頭中的"User-Agent:
"重寫一個(gè)站點(diǎn)的主頁,可以這樣寫:
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等等)。如果上述條件都不滿足(使用的是其他瀏覽器),則你得到的是一個(gè)標(biāo)準(zhǔn)的主
頁。
說明
|
打開或關(guān)閉運(yùn)行時(shí)的重寫引擎 |
語法
|
RewriteEngine on|off
|
默認(rèn)值
|
RewriteEngine off
|
作用域
|
server config, virtual host, directory, .htaccess |
覆蓋項(xiàng)
|
FileInfo |
狀態(tài)
|
擴(kuò)展(E) |
模塊
|
mod_rewrite |
RewriteEngine
指令打開或關(guān)閉運(yùn)行時(shí)的重寫引擎。如果設(shè)置為off
,則此模塊在運(yùn)行時(shí)不執(zhí)行任何重寫操作, 同時(shí)也不更新SCRIPT_URx
環(huán)境變量。
使用該指令可以使此模塊無效,而無須注釋所有的RewriteRule
指令!
注意:默認(rèn)情況下,重寫配置是不可繼承的,也就是必須在每個(gè)需要使用重寫引擎的虛擬主機(jī)中設(shè)置一個(gè)RewriteEngine on
指令。
此指令設(shè)置mod_rewrite為了和RewriteMap
程序通訊而使用的同步鎖文件的名稱。 在需要使用重寫映射表程序(rewriting map-program)時(shí),它必須是一個(gè)本地路徑(而不能是一個(gè)NFS掛接設(shè)備)。對其他類型的重寫映射表(rewriting map),則無此要求。
說明
|
設(shè)置重寫引擎日志的文件名 |
語法
|
RewriteLog file-path
|
作用域
|
server config, virtual host |
狀態(tài)
|
擴(kuò)展(E) |
模塊
|
mod_rewrite |
RewriteLog
指令設(shè)置用于記錄所有重寫操作的日志文件的名稱。如果此文件名不以斜杠('/
')開頭,則它是相對于Server Root的,此指令應(yīng)該在每個(gè)服務(wù)器級別的配置中僅僅出現(xiàn)一次。
如果要關(guān)閉對重寫操作的記錄,不推薦將Filename設(shè)為/dev/null
,因?yàn)椋m然重寫引擎不能輸出記錄了,但仍會在內(nèi)部建立這個(gè)日志文件,這樣會使服務(wù)器速度降低,而且對管理員毫無益處!要關(guān)閉日志,可以刪除或注解RewriteLog
指令, 或者使用"RewriteLogLevel 0
"的設(shè)置
安全
參見
安全方面的提示文檔,其中講述了為什么如果存放日志的目錄對除了啟動服務(wù)器以外的用戶是可寫的會帶來安全隱患。
示例
RewriteLog "/usr/local/var/apache/logs/rewrite.log"
說明
|
設(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)閉所有重寫操作的記錄。
較高的Level值會使Apache服務(wù)器速度急劇下降!大于2的Level值只用于調(diào)試目的!
說明
|
定義用于關(guān)鍵詞查找的映射函數(shù) |
語法
|
RewriteMap MapNameMapType:MapSource
|
作用域
|
server config, virtual host |
狀態(tài)
|
擴(kuò)展(E) |
模塊
|
mod_rewrite |
兼容性
|
Apache 2.0.41 及以后的版本中可以使用不同的dbm類型 |
RewriteMap
指令定義了一個(gè)映射表(Rewriting Map),映射函數(shù)將使用該表來查找關(guān)鍵字然后插入/替換字段。此查找操作的源可以是多種類型。
MapName
是映射表的名稱,指定了一個(gè)映射函數(shù),用于重寫規(guī)則的字符串替換,它可以是下列形式之一:
${
MapName
:
LookupKey
}
${
MapName
:
LookupKey
|
DefaultValue
}
如果使用了這樣的形式,則會在MapName中查找關(guān)鍵詞LookupKey。如果找到了,則被替換成SubstValue; 如果沒有找到,則被替換成DefaultValue,如果沒有指定DefaultValue,則被替換成空字符串。
例如,你可能定義這樣一個(gè)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是一個(gè)純文本文件,包含空行、注釋行(以字符'#'打頭),以及每行一個(gè)的替換對,如下所示:
MatchingKeySubstValue
例子
## 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
-
隨機(jī)純文本
MapType: rnd
, MapSource: 有效的Unix文件系統(tǒng)文件名
這個(gè)與上述的標(biāo)準(zhǔn)純文本很相似,但它有一個(gè)特殊的后處理特性:查找完畢后,會解析其中包含的"|
"符號(含義為"或")。 也就是說,會隨機(jī)地選擇其中之一作為返回值。雖然這看似毫無意義,但設(shè)計(jì)它的意圖是在一個(gè)查找值是服務(wù)器名稱的反向代理環(huán)境中實(shí)現(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)文件名
這里的源是一個(gè)二進(jìn)制格式的DBM文件,包含了與純文本相同的內(nèi)容,但是因?yàn)樗袃?yōu)化了的特殊表現(xiàn)形式,使它的查找速度明顯快得多。 此type可以是sdbm, gdbm, ndbm, db(由編譯時(shí)配置決定)。如果省略type,則使用編譯時(shí)選擇的缺省值。 你可以使用任何DBM工具或者下列Perl腳本來創(chuàng)建這個(gè)文件,但必須保證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);
-
內(nèi)部函數(shù)
MapType: int
, MapSource: Apache內(nèi)部函數(shù)
這里的源是一個(gè)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)制編碼為特殊字符
-
外部的重寫程序
MapType: prg
, MapSource: 有效的Unix文件系統(tǒng)文件名
這里的源是一個(gè)程序,而不是一個(gè)映射表文件。程序設(shè)計(jì)語言可以隨意選擇,但最終結(jié)果必須是可執(zhí)行的(或者是目標(biāo)代碼,或者是首行為'#!/path/to/interpreter
'的腳本)。
此程序僅在Apache服務(wù)器啟動時(shí)啟動一次,隨后通過stdin
和stdout
文件句柄與重寫引擎交互。 對每個(gè)映射函數(shù)的查找操作,它從stdin
接收以回車結(jié)束的查找關(guān)鍵詞,然后把查找的結(jié)果以回車結(jié)束反饋到stdout
,如果查找失敗,則返回四個(gè)字符的字符串"NULL"(對給定的關(guān)鍵詞沒有對應(yīng)的值)。此程序的最簡單形式是一個(gè)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緩沖(一個(gè)常見的錯(cuò)誤),它會導(dǎo)致死循環(huán)!所以上述例子中才會使用"$|=1
"來預(yù)防。 - 使用
RewriteLock
指令定義一個(gè)鎖文件,用于同步mod_rewrite和此程序之間的通訊。默認(rèn)是沒有同步操作的。
RewriteMap
指令可以多次出現(xiàn)。對每個(gè)映射函數(shù)都可以使用一個(gè)RewriteMap
指令來定義其重寫映射表。雖然不能在目錄上下文(per-directory context)中定義映射表,但是完全可以在其中使用映射表。
注意
對于純文本和DBM格式的文件,已經(jīng)查找過的關(guān)鍵詞會被緩存在內(nèi)核中,直到映射表的mtime
改變了或者服務(wù)器重啟了。這樣,你可以把每個(gè)請求都會用到的映射函數(shù)放在規(guī)則中,這是沒有問題的,因?yàn)橥獠坎檎抑贿M(jìn)行一次。
說明
|
為重寫引擎設(shè)置一些特殊的選項(xiàng) |
語法
|
RewriteOptions Options
|
作用域
|
server config, virtual host, directory, .htaccess |
覆蓋項(xiàng)
|
FileInfo |
狀態(tài)
|
擴(kuò)展(E) |
模塊
|
mod_rewrite |
兼容性
|
MaxRedirects 在2.1及以后的版本中已經(jīng)不可用 |
RewriteOptions
指令為當(dāng)前服務(wù)器級和目錄級的配置設(shè)置一些選項(xiàng)。Option當(dāng)前僅可以是如下值:
-
inherit
- 此值強(qiáng)制當(dāng)前配置繼承其父配置。在虛擬主機(jī)級配置中,它意味著主服務(wù)器的映射表、條件和規(guī)則可以被繼承。在目錄級配置中,它意味著其父目錄的
.htaccess
中的條件和規(guī)則可以被繼承。
說明
|
為重寫引擎定義重寫規(guī)則 |
語法
|
RewriteRule PatternSubstitution [flags]
|
作用域
|
server config, virtual host, directory, .htaccess |
覆蓋項(xiàng)
|
FileInfo |
狀態(tài)
|
擴(kuò)展(E) |
模塊
|
mod_rewrite |
兼容性
|
cookie-flag在Apache 2.0.40及以后的版本中可用 |
RewriteRule
指令是重寫引擎的根本。此指令可以多次使用。每個(gè)指令定義一個(gè)簡單的重寫規(guī)則。這些規(guī)則的定義順序尤為重要——在運(yùn)行時(shí),規(guī)則是按這個(gè)順序逐一生效的。
Pattern
是一個(gè)作用于當(dāng)前URL的perl兼容的正則表達(dá)式。"當(dāng)前URL"是指該規(guī)則生效時(shí)刻的URL的值。它可能與被請求的URL截然不同,因?yàn)槠渌?guī)則可能在此之前已經(jīng)發(fā)生匹配并對它做了改動。
正則表達(dá)式的一些用法示例:
文本
.
任意一個(gè)單字符
[
chars]
字符類: "chars"中的任意一個(gè)字符
[^
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è)置一個(gè)選擇的邊界,或用于生成后引用:
在RewriteRule中可以用 $
N 引用第N個(gè)分組)
錨
^
錨定到行首
$
錨定到行尾
轉(zhuǎn)義
\
c 對給定的字符c進(jìn)行轉(zhuǎn)義
(比如對".[]()
"進(jìn)行轉(zhuǎn)義,等等)
更多有關(guān)正則表達(dá)式的資料請參見perl正則表達(dá)式手冊頁("perldoc perlre")。另外,在mod_rewrite中,還可以使用否字符('!
')前綴實(shí)現(xiàn)反轉(zhuǎn)。比如:"如果當(dāng)前URL不與模式相匹配"它用于使用否定式匹配模式較容易描述的某些情況,或者作為最后一條規(guī)則。
注意
使用否字符以反轉(zhuǎn)匹配模式時(shí),匹配模式中不能使用分組的通配成分。由于模式不匹配而使分組的內(nèi)容是空的,所以它是不可能實(shí)現(xiàn)的。 因此,如果使用了否定式匹配模式,那么后繼的字符串中就不能使用$N
重寫規(guī)則中的Substitution是當(dāng)原始URL與Pattern相匹配時(shí),用來替代(或替換)的字符串。除了純文本,還可以包含:
- 對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é)(見下文)。
'-
'是一個(gè)特殊的替換串,意思是不替換。它可以用于僅僅匹配某些URL而無須替換的情況,比如,在發(fā)生替換前,允許以C(chain)標(biāo)記連接的多個(gè)匹配模式同時(shí)起作用。
此外,在Substitution之后還可以追加[
flags]
標(biāo)記作為RewriteRule
指令的第三個(gè)參數(shù)。Flags是一個(gè)包含以逗號分隔的下列標(biāo)記的列表:
- '
chain|C
'(鏈接下一規(guī)則)
此標(biāo)記使當(dāng)前規(guī)則與下一個(gè)規(guī)則相鏈接。它產(chǎn)生這樣的效果:如果一個(gè)規(guī)則被匹配,則繼續(xù)處理其后繼規(guī)則,也就是這個(gè)標(biāo)記不起作用;如果該規(guī)則不被匹配,則其后繼規(guī)則將被跳過。比如,在一個(gè)目錄級規(guī)則中執(zhí)行一個(gè)外部重定向時(shí),你可能需要刪除".www
"(此處不應(yīng)該出現(xiàn)".www
")。
- '
cookie|CO=
NAME:VAL:domain[:lifetime[:path]]'(設(shè)置cookie)
在客戶端設(shè)置一個(gè)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è)置多個(gè)變量。這些變量可以在其后許多情況下被間接引用,通常是在XSSI(<!--#echo var="VAR"-->
)或CGI($ENV{'VAR'}
)中,也可以在后繼的RewriteCond
指令的CondPattern參數(shù)中通過%{ENV:VAR}
引用。使用它可以記住從URL中剝離的信息。
- '
forbidden|F
'(強(qiáng)制禁止URL)
強(qiáng)制禁止當(dāng)前URL,也就是立即反饋一個(gè)HTTP響應(yīng)碼403(被禁止的)。使用這個(gè)標(biāo)記,可以鏈接若干個(gè)RewriteConds來有條件地阻塞某些URL。
- '
gone|G
'(強(qiáng)制廢棄URL)
強(qiáng)制當(dāng)前URL為已廢棄,也就是立即反饋一個(gè)HTTP響應(yīng)碼410(已廢棄的)。使用這個(gè)標(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
命令。這個(gè)標(biāo)記用于阻止當(dāng)前已被重寫的URL被后繼規(guī)則再次重寫。例如,使用它可以重寫根路徑的URL('/
')為實(shí)際存在的URL(比如:'/e/www/
')。
- '
next|N
'(從頭再來)
重新執(zhí)行重寫操作(從第一個(gè)規(guī)則重新開始)。此時(shí)再次進(jìn)行處理的URL已經(jīng)不是原始的URL了,而是經(jīng)最后一個(gè)重寫規(guī)則處理過的URL。它對應(yīng)于Perl中的next
命令或C語言中的continue
命令。此標(biāo)記可以重新開始重寫操作(立即回到循環(huán)的開頭)。但是要小心,不要制造死循環(huán)!
- '
nocase|NC
'(忽略大小寫)
它使Pattern忽略大小寫,也就是在Pattern與當(dāng)前URL匹配時(shí),'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)向到一個(gè)安全的請求'/bar?arg=P1=zed
'。
- '
nosubreq|NS
'(不對內(nèi)部子請求進(jìn)行處理)
在當(dāng)前請求是一個(gè)內(nèi)部子請求時(shí),此標(biāo)記強(qiáng)制重寫引擎跳過該重寫規(guī)則。比如,在mod_include
試圖搜索目錄默認(rèn)文件(index.xxx
)時(shí),Apache會在內(nèi)部產(chǎn)生子請求。對于子請求,重寫規(guī)則不一定有用,而且如果整個(gè)規(guī)則集都起作用,它甚至可能會引發(fā)錯(cuò)誤。所以,可以用這個(gè)標(biāo)記來排除某些規(guī)則。
使用原則:如果你為URL添加了CGI腳本前綴,以強(qiáng)制它們由CGI腳本處理,但對子請求處理的出錯(cuò)率(或者資源開銷)很高,在這種情況下,可以使用這個(gè)標(biāo)記。
- '
proxy|P
'(強(qiáng)制為代理)
此標(biāo)記使替換成分被內(nèi)部地強(qiáng)制作為代理請求發(fā)送,并立即中斷重寫處理,然后把處理移交給mod_proxy模塊。你必須確保此替換串是一個(gè)能夠被mod_proxy處理的有效URI(比如以http://
hostname開頭),否則將得到一個(gè)代理模塊返回的錯(cuò)誤。使用這個(gè)標(biāo)記,可以把某些遠(yuǎn)程成分映射到本地服務(wù)器域名空間,從而增強(qiáng)了ProxyPass指令的功能。
注意:要使用這個(gè)功能,必須已經(jīng)啟用了mod_proxy
模塊。
- '
passthrough|PT
'(移交給下一個(gè)處理器)
此標(biāo)記強(qiáng)制重寫引擎將內(nèi)部request_rec
結(jié)構(gòu)中的uri
字段設(shè)置為filename
字段的值,這個(gè)小小的修改使得RewriteRule
指令的輸出能夠被(從URI轉(zhuǎn)換到文件名的)Alias
, ScriptAlias
, Redirect
等指令進(jìn)行后續(xù)處理[原文:This flag is just a hack to enable post-processing of the output of RewriteRule
directives, using Alias
, ScriptAlias
, Redirect
, and other directives from various URI-to-filename translators.]。舉一個(gè)能說明其含義的例子: 如果要將/abc
重寫為/def
, 然后再使用mod_alias
將/def
轉(zhuǎn)換為/ghi
,可以這樣:
RewriteRule ^/abc(.*) /def$1 [PT]
Alias /def /ghi
如果省略了PT
標(biāo)記,雖然將uri=/abc/...
重寫為filename=/def/...
的部分運(yùn)作正常,但是后續(xù)的mod_alias
在試圖將URI轉(zhuǎn)換到文件名時(shí)會遭遇失效。
注意:如果需要混合使用多個(gè)將URI轉(zhuǎn)換到文件名的模塊時(shí),就必須使用這個(gè)標(biāo)記。。此處混合使用mod_alias
和mod_rewrite
就是個(gè)典型的例子。
- '
qsappend|QSA
'(追加查詢字符串)
此標(biāo)記強(qiáng)制重寫引擎在已有的替換字符串中追加一個(gè)查詢字符串,而不是簡單的替換。如果需要通過重寫規(guī)則在請求串中增加信息,就可以使用這個(gè)標(biāo)記。
- '
redirect|R
[=code]'(強(qiáng)制重定向)
若Substitution以http://thishost[:thisport]/
(使新的URL成為一個(gè)URI)開頭,可以強(qiáng)制性執(zhí)行一個(gè)外部重定向。如果沒有指定code,則產(chǎn)生一個(gè)HTTP響應(yīng)碼302(臨時(shí)性移動)。如果需要使用在300-400范圍內(nèi)的其他響應(yīng)代碼,只需在此指定即可(或使用下列符號名稱之一:temp
(默認(rèn)), permanent
, seeother
)。使用它可以把規(guī)范化的URL反饋給客戶端,如將"/~
"重寫為"/u/
",或始終對/u/
user加上斜杠,等等。
注意:在使用這個(gè)標(biāo)記時(shí),必須確保該替換字段是一個(gè)有效的URL。否則,它會指向一個(gè)無效的位置!并且要記住,此標(biāo)記本身只是對URL加上http://thishost[:thisport]/
前綴,重寫操作仍然會繼續(xù)進(jìn)行。通常,你還會希望停止重寫操作而立即重定向,那么就還需要使用'L'標(biāo)記。
- '
skip|S
=num'(跳過后繼規(guī)則)
此標(biāo)記強(qiáng)制重寫引擎跳過當(dāng)前匹配規(guī)則之后的num個(gè)規(guī)則。它可以模擬if-then-else結(jié)構(gòu):最后一個(gè)規(guī)則是then從句,而被跳過的skip=N
個(gè)規(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]
注意:絕對URL的替換
當(dāng)替換字段以"http://thishost[:thisport]
"作為前綴時(shí),mod_rewrite
會將它自動剝離出去。在配合生成主機(jī)名部分的映射函數(shù)使用的時(shí)候,這個(gè)對隱含的外部重定向URL的簡化操作是有用的而且是重要的。下面的第一個(gè)例子有助于理解這點(diǎn)。
謹(jǐn)記:由于此功能的存在,以"http://thishost
"為前綴的無條件外部重定向到自身所在的服務(wù)器是無效的。要實(shí)現(xiàn)一個(gè)到自身的重定向,必須使用R標(biāo)記。
注意:查詢字符串
Pattern不會按照查詢字符串進(jìn)行匹配。為了達(dá)到這個(gè)目的,你必須使用一個(gè)帶有%{QUERY_STRING}
變量的RewriteCond
指令。當(dāng)然,你也可以在替換字符串中創(chuàng)建包含查詢字符串的URL:在替換字符串串中使用問號,以標(biāo)明其后的部分應(yīng)該被重新注入到QUERY_STRING中。而要刪除一個(gè)已有的請求串,則可以用問號來終結(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)部代理