天天看點

.htaccess中的apache rewrite規則詳解

.htaccess中的apache rewrite寫法:

RewriteEngine On

RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$

RewriteCond %{REQUEST_URI} !^/blog/

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ /blog/$1

# 沒有輸入檔案名的預設到到首頁

RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$

RewriteRule ^(/)?$ blog/index.php [L]

下面我開始解說一下上面的意思:

【RewriteEngine On】表示重寫引擎開,關閉off,作用就是友善的開啟或關閉以下的語句,這樣就不需要一條一條的注釋語句了。

【RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$】

這是重寫條件,前面%{HTTP_HOST}表示目前通路的網址,隻是指字首部分,格式是www.xxx.com不包括“http://”和“/”,^表示字元串開始,$表示字元串結尾,\.表示轉義的. ,如果不轉義也行,推薦轉義,防止有些伺服器不支援,?表示前面括号www\.出現0次或1次,這句規則的意思就是如果通路的網址是xxx.com或者www.xxx.com就執行以下的語句,不符合就跳過。

【RewriteCond %{REQUEST_URI} !^/blog/】

也是重寫條件,%{REQUEST_URI}表示通路的相對位址,就是相對根目錄的位址,就是域名/後面的成分,格式上包括最前面的“/”,!表示非,這句語句表示通路的位址不以/blog/開頭,隻是開頭^,沒有結尾$

【RewriteCond %{REQUEST_FILENAME} !-f】

【RewriteCond %{REQUEST_FILENAME} !-d】

這兩句語句的意思是請求的檔案或路徑是不存在的,如果檔案或路徑存在将傳回已經存在的檔案或路徑

【RewriteRule ^(.*)$ /blog/$1】重寫規則,最重要的部分,意思是當上面的RewriteCond條件都滿足的時候,将會執行此重寫規則,^(.*)$是一個正則表達的比對,比對的是目前請求的URL,^(.*)$意思是比對目前URL任意字元,.表示任意單個字元,*表示比對0次或N次(N>0),後面/blog/$1是重寫成分,意思是将前面比對的字元重寫成/blog/$1,這個$1表示反向比對,引用的是前面第一個圓括号的成分,即^(.*)$中的.* ,其實這兒将會出現一個問題,後面讨論。

【RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$】

【RewriteRule ^(/)?$ blog/index.php [L]】

這兩句的意思是指請求的host位址是www.xxx.com是,如果位址的結尾隻有0個或者1個“/”時,将會重寫到子目錄下的首頁,我猜想這主要因為重寫後的位址是不能自動尋找首頁的,需要自己指定。

現在說說出現的問題,RewriteRule ^(.*)$ /blog/$1前部分^(.*)$将會比對目前請求的url,例如:請求網址是http://www.xxx.com/a.html,到底是比對整個http://www.xxx.com/a.html,還是隻比對/a.html即反斜杠後面的成分,還是隻比對a.html。

答案是:根據RewriteBase規則規定,如果rewritebase 為/,将會比對a.html,不帶前面的反斜杠,是以上條語句應該寫成RewriteRule ^(.*)$ blog/$1(不帶/),不過實際應用上帶上前面的反斜杠,也可以用,可能帶不帶都行。現在問題出來了,如果不設定rewritebase 為/ ,将會比對整個網址http://www.xxx.com/a.html,顯然這是錯誤的,是以應該添加這條:

RewiteBase /

還有一個問題是,不能保證每個人輸入的網址都是小寫的,如果輸入大寫的呢,linux系統是區分大小寫的,是以應該在RewriteCond後添加[NC]忽略大小寫的。

至此,完整的語句應該是:

####start####

RewriteEngine On

RewiteBase /

RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$ [NC]

RewriteCond %{REQUEST_URI} !^/blog/

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ blog/$1

# 沒有輸入檔案名的預設到到首頁

RewriteCond %{HTTP_HOST} ^(www\.)?xxx\.com$ [NC]

RewriteRule ^(/)?$ blog/index.php [L]

####end####

如果後面還繼續有語句的,就不應該加上最後的[L],因為這是表示最後一條語句的意思

防盜鍊的語句,同樣需要添加RewiteBase /,如下:

RewriteEngine on

RewiteBase /

RewriteCond %{HTTP_REFERER} !^$ [NC]

RewriteCond %{HTTP_REFERER} !xxx.info [NC]

RewriteRule \.(jpg|gif|png|bmp|swf|jpeg)$ /error/daolian.gif [R,NC,L]

如果後面還繼續有語句的,就不應該加上最後的[L],/error/daolian.gif為别人盜鍊時顯示的圖檔。

下面附上簡單的文法規則和flags:

【RewriteCond文法:】

RewriteCond TestString CondPattern [flags]

rewritecond的其他用法:

‘-d’(目錄)

将TestString視為一個路徑名并測試它是否為一個存在的目錄。

‘-f’(正常檔案)

将TestString視為一個路徑名并測試它是否為一個存在的正常檔案。

‘-s’(非空的正常檔案)

将TestString視為一個路徑名并測試它是否為一個存在的、尺寸大于0的正常檔案。

‘-l’(符号連接配接)

将TestString視為一個路徑名并測試它是否為一個存在的符号連接配接。

‘-x’(可執行)

将TestString視為一個路徑名并測試它是否為一個存在的、具有可執行權限的檔案。該權限由作業系統檢測。

‘-F’(對子請求存在的檔案)

檢查TestString是否為一個有效的檔案,而且可以在伺服器目前的通路控制配置下被通路。它使用一個内部子請求來做檢查,由于會降低伺服器的性能,是以請謹慎使用!

‘-U’(對子請求存在的URL)

檢查TestString是否為一個有效的URL,而且可以在伺服器目前的通路控制配置下被通路。它使用一個内部子請求來做檢查,由于會降低伺服器的性能,是以請謹慎使用!

【RewriteRule文法:】

RewriteRule Pattern Substitution [flags]

【flags】:

‘chain|C’(連結下一規則)

此标記使目前規則與下一個規則相連結。它産生這樣的效果:如果一個規則被比對,則繼續處理其後繼規則,也就是這個标記不起作用;如果該規則不被比對,則其後繼規則将被跳過。比如,在一個目錄級規則中執行一個外部重定向時,你可能需要删除”.www”(此處不應該出現”.www”)。

‘cookie|CO=NAME:VAL:domain[:lifetime[:path]]’(設定cookie)

在用戶端設定一個cookie。cookie的名稱是NAME,值是VAL。domain是該cookie的域,比如’.apache.org’,可選的lifetime是cookie的有效期(分鐘),可選的path是cookie的路徑。

‘env|E=VAR:VAL’(設定環境變量)

此标記将環境變量VAR的值為VAL,VAL可以包含可擴充的正規表達式反向引用($N和%N)。此标記可以多次使用以設定多個變量。這些變量可以在其後許多情況下被間接引用,通常是在XSSI(<!–#echo var=”VAR”–>)或CGI($ENV{‘VAR’})中,也可以在後繼的RewriteCond指令的CondPattern參數中通過%{ENV:VAR}引用。使用它可以記住從URL中剝離的資訊。

‘forbidden|F’(強制禁止URL)

強制禁止目前URL,也就是立即回報一個HTTP響應碼403(被禁止的)。使用這個标記,可以連結若幹個RewriteConds來有條件地阻塞某些URL。

‘gone|G’(強制廢棄URL)

強制目前URL為已廢棄,也就是立即回報一個HTTP響應碼410(已廢棄的)。使用這個标記,可以标明頁面已經被廢棄而不存在了。

‘handler|H=Content-handler’(強制指定内容處理器)

強自制定目标檔案的内容處理器為Content-handler。例如,用來模拟mod_alias子產品的ScriptAlias指令,以強制映射檔案夾内的所有檔案都由”cgi-script”處理器處理。

‘last|L’(結尾規則)

立即停止重寫操作,并不再應用其他重寫規則。它對應于Perl中的last指令或C語言中的break指令。這個标記用于阻止目前已被重寫的URL被後繼規則再次重寫。例如,使用它可以重寫根路徑的URL(‘/’)為實際存在的URL(比如:’/e/www/’)。

‘next|N’(從頭再來)

重新執行重寫操作(從第一個規則重新開始)。此時再次進行處理的URL已經不是原始的URL了,而是經最後一個重寫規則處理過的URL。它對應于Perl中的next指令或C語言中的continue指令。此标記可以重新開始重寫操作(立即回到循環的開頭)。但是要小心,不要制造死循環!

‘nocase|NC’(忽略大小寫)

它使Pattern忽略大小寫,也就是在Pattern與目前URL比對時,’A-Z’和’a-z’沒有差別。

‘noescape|NE’(在輸出中不對URI進行轉義)

此标記阻止mod_rewrite對重寫結果應用正常的URI轉義規則。 一般情況下,特殊字元(‘%’, ‘$’, ‘;’等)會被轉義為等值的十六進制編碼(‘%25′, ‘%24′, ‘%3B’等)。此标記可以阻止這樣的轉義,以允許百分号等符号出現在輸出中,比如:

RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE]

可以使’/foo/zed轉向到一個安全的請求’/bar?arg=P1=zed’。

‘nosubreq|NS’(不對内部子請求進行處理)

在目前請求是一個内部子請求時,此标記強制重寫引擎跳過該重寫規則。比如,在mod_include試圖搜尋目錄預設檔案(index.xxx)時,Apache會在内部産生子請求。對于子請求,重寫規則不一定有用,而且如果整個規則集都起作用,它甚至可能會引發錯誤。是以,可以用這個标記來排除某些規則。

使用原則:如果你為URL添加了CGI腳本字首,以強制它們由CGI腳本處理,但對子請求處理的出錯率(或者資源開銷)很高,在這種情況下,可以使用這個标記。

‘proxy|P’(強制為代理)

此标記使替換成分被内部地強制作為代理請求發送,并立即中斷重寫處理,然後把處理移交給mod_proxy子產品。你必須確定此替換串是一個能夠被mod_proxy處理的有效URI(比如以http://hostname開頭),否則将得到一個代理子產品傳回的錯誤。使用這個标記,可以把某些遠端成分映射到本地伺服器域名空間,進而增強了ProxyPass指令的功能。

注意:要使用這個功能,必須已經啟用了mod_proxy子產品。

‘passthrough|PT’(移交給下一個處理器)

此标記強制重寫引擎将内部request_rec結構中的uri字段設定為filename字段的值,這個小小的修改使得RewriteRule指令的輸出能夠被(從URI轉換到檔案名的)Alias, ScriptAlias, Redirect等指令進行後續處理[原文: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.]。舉一個能說明其含義的例子: 如果要将/abc重寫為/def, 然後再使用mod_alias将/def轉換為/ghi,可以這樣:

RewriteRule ^/abc(.*) /def$1 [PT]

Alias /def /ghi

如果省略了PT标記,雖然将uri=/abc/…重寫為filename=/def/…的部分運作正常,但是後續的mod_alias在試圖将URI轉換到檔案名時會遭遇失效。

注意:如果需要混合使用多個将URI轉換到檔案名的子產品時,就必須使用這個标記。。此處混合使用mod_alias和mod_rewrite就是個典型的例子。

‘qsappend|QSA’(追加查詢字元串)

此标記強制重寫引擎在已有的替換字元串中追加一個查詢字元串,而不是簡單的替換。如果需要通過重寫規則在請求串中增加資訊,就可以使用這個标記。

‘redirect|R [=code]‘(強制重定向)

若Substitution以http://thishost[:thisport]/(使新的URL成為一個URI)開頭,可以強制性執行一個外部重定向。如果沒有指定code,則産生一個HTTP響應碼302(臨時性移動)。如果需要使用在300-400範圍内的其他響應代碼,隻需在此指定即可(或使用下列符号名稱之一:temp(預設), permanent, seeother)。使用它可以把規範化的URL回報給用戶端,如将”/~”重寫為”/u/”,或始終對/u/user加上斜杠,等等。

注意:在使用這個标記時,必須確定該替換字段是一個有效的URL。否則,它會指向一個無效的位置!并且要記住,此标記本身隻是對URL加上http://thishost[:thisport]/字首,重寫操作仍然會繼續進行。通常,你還會希望停止重寫操作而立即重定向,那麼就還需要使用’L'标記。

’skip|S=num’(跳過後繼規則)

此标記強制重寫引擎跳過目前比對規則之後的num個規則。它可以模拟if-then-else結構:最後一個規則是then從句,而被跳過的skip=N個規則是else從句。注意:它和’chain|C’标記是不同的!

‘type|T=MIME-type’(強制MIME類型)

強制目标檔案的MIME類型為MIME-type,可以用來基于某些特定條件強制設定内容類型。比如,下面的指令可以讓.php檔案在以.phps擴充名調用的情況下由mod_php按照PHP源代碼的MIME類型(application/x-httpd-php-source)顯示:

RewriteRule ^(.+\.php)s$ $1 [T=application/x-httpd-php-source]

繼續閱讀