Apache Rewrite 大全

Apache Rewrite 大全php

Apacherewrite模塊,提供了一個基於規則的重寫(rewrite,也許譯爲重構更爲合適)引擎,來實時重寫發送到Apache的請求URL。因功能極其強大,被稱爲URL重寫的瑞士軍刀html

這個模塊使用一個基於正則表達式解析器開發的重寫引擎,根據web管理員定義的規則來實時(on the fly)重寫請求URL。它支持任意數目的重寫規則,以及附加到一條規則上的任意數目的規則條件,從而提供了一套很是靈活和功能強大的URL處理機制。URL處理操做的實施與否,依賴於各類各樣的條件檢查,如檢查服務器變量、環境變量、HTTP頭字段、時間戳的值,甚至外部數據庫的檢索結果。這個模塊能夠在服務器範圍內(http.conf)、目錄範圍內(.htaccess)或請求串(query-string)的一部分處理有關的URL。重寫的結果URL,能夠指向一個站內的處理程序、指向站外的重定向或者一個站內的代理。與靈活和功能強大相隨的是設置的複雜,別期望一天內弄明白整個模塊。(因此,這個學習筆記也分了幾部分:)
web

內部處理過程正則表達式

API階段
首先,Apache處理HTTP請求是分階段進行的,Apache API爲每一個階段提供了一個鉤子(hook)Mod_rewrite使用了其中的兩個鉤子:一個用來在HTTP請求被讀取但尚未訪問受權驗證以前進行URL_to_filename轉換,一個用來在受權驗證完成且目錄設置文件(.htaccess)讀取以後、但內容處理器(content handler)被調用以前激化,進行修補(fixup).所以,當一個請求到達,Apache決定了相關的服務器(或虛擬服務器)之後進行URL_to_filename階段,重寫引擎(rewrite engine)開始處理服務器設置中的重寫指令(mod_rewrite directives).接下來幾個階段事後進入修補階段,此時最終的數據所在的物理目錄已經找到,目錄配置中的重寫指令開始執行。在這兩個階段,mod_rewrite都是將URL重寫爲新的URL或文件名,因此看起來並無明顯的區別。對API的這種應用,並非一開始就是這樣設計的,而是Apache1.x不得已而爲之。爲了搞清這個問題,如下兩點須要記住。
1)雖然mod_rewrite能進行URLURLURL到文件名字甚至文件名字到文件名字的轉換,API(1.x)目前提供了一個URL_to_filename轉換。在Apache2.0中,這兩個鉤子會被加進去,整個過程會更加清晰。一個事實必須清楚的記得:ApacheURL_to_filename鉤子中,作得比API設計的功能更多。
2)難以想象的是,mod_rewrite能在目錄範圍內(如根據.htaccess文件的指令配置)進行URL處理,雖然URL很早就已經被轉換爲文件名字了。只因此會如此,是由於.htaccess文件存在於文件系統中。也就是說,在這個階段來進行URL處理,是很是晚的時候了。爲了解決這個"先有雞仍是先有蛋"的問題,mod_rewrite用了一個小技巧:當在目錄範圍內處理URL/filename時,mod_rewrite先將文件名逆轉回相關的URL(雖然一般是不可能的,但請參見下面用以實現這個技巧的RewriteBase指令),而後據這個新URL生成一個站內的子請求(internal sub-request),這又重開始了API進程。Mod_rewrite儘可能使這些複雜的步驟對用戶透明,但應要記住:雖然目錄範圍URL的真正處理過程很快很高效,但這一階段會由於這個"雞和蛋"的問題而變得很慢和低效。從另外一方面來看,這也是mod_rewrite提供給普通用戶進行目錄範圍內的URL處理的惟一途徑.
規則集(RewriteRule指令集合)處理過程
mod_rewrite在上述的兩個API階段被激活時,它會從它的配置數據結構(在開始服務器上下文(per-server context)或目錄上下文(per-directory context)時建立的)中讀取配置的規則集,而後URL重寫引擎啓動來執行包含的規則集(一個或多條規則以及它們的條件)。兩種上下文中的處理過程都是同樣的,差異只是在最後的結果處理過程上。
規則集中規則的順序是很是重要的,由於重寫引擎以特定的順序來處理它們。重寫引擎順序遍歷規則集,當一條規則匹配時,引擎會去遍歷與它相關的條件集(RewriteCond指令集合).因爲歷史的緣由,條件集先被列出來,所以控制流流程有點曲折(long-winded).如圖一所示:
mod_rewrite_fig1.gif
正如所看到的,首先URL會與每條規則的模板(pattern)比較,當匹配失敗時,當即中止對當前規則的處理進入下一條規則。當匹配成功時,mod_rewrite尋找相關的規則條件。若是找不到相關的條件,則直接執行規則中定義的替換,而後回到規則遍歷的過程。若是找到了相關的條件,則啓動一個內部循環,依次檢查各個條件。對於檢查,咱們不是拿一個模板來匹配當前的URL,而是先建立一個TestString串,將串內的變量、後向引用(bakc-reference)、查詢結果(map lookups)等展開,而後用這個TestString和條件式中的CondPattern進行匹配,若是匹配失敗,則整個條件集且這個規則都再也不執行,重要回到規則遍歷中;若是匹配成功,則檢查下一個條件,若是全部的條件都知足,則執行規則中定義的替換動做。
特殊字符的轉義
既然基於正則式,則固然會有特殊字符的問題。在1.3.20版本的Apache中,經過在特殊字符前加一個「\」來將TestStringSustitution串的特殊字符轉義。
正則式的後向引用
mod_rewrite_fig2.gif 有一點須要記住:一旦在模板(pattern)或條件模板(CondPattern)中使用了括號,則後向引用已經自動產生了,你能夠在SustitutionTestString中經過$N%N來引用相關的值。如圖,描述了後向引用的值能夠傳到的位置。數據庫

配置指令(Configuration Directives)express

 

指令apache

語法瀏覽器

默認值緩存

說明tomcat

備註

RewriteEngine

RewriteEngine on|off

Off

開關重構引擎

默認時不能繼承,故每一個虛擬主機都要有本身的開關指令。

RewriteOptions

RewriteOptions Option

MaxRedirects=10

設置一些特殊參數

inherit:配置是否繼承,MaxRedirects=number:內部重定向次數

RewriteLog

RewriteLog file-path

None

設定重寫log文件

RewriteLogLevel 0來禁止日誌

RewriteLogLevel

RewriteLogLevel Level

RewriteLogLevel 0

設置日誌級別

表示沒有,2以上用於debug9及以上表示所有信息

RewriteLock

RewriteLock file-path

None

設置RewriteMap程序的同步鎖文件

要求是本地文件,此文件只對rewriting map-program有效。

RewriteMap

RewriteMap MapName MapType:MapSource

Notused per default

定義重寫影射

具體說明參見文檔

RewriteBase

RewriteBase URL-path

physical directory path

設置目錄範圍內重寫的基本URL

具體說明參見文檔

RewriteCond

RewriteCond TestString CondPattern

None

定義規則條件

具體說明參見文檔

RewriteRule

RewriteRule Pattern Substitution

None

定義重寫規則

具體說明參見文檔

 

 

今天學習重寫規則的語法。

RewriteRule
Syntax: RewriteRule Pattern Substitution [flags]
一條RewriteRule指令,定義一條重寫規則,規則間的順序很是重要。對Apache1.2及之後的版本,模板(pattern)是一個POSIX正則式,用以匹配當前的URL。當前的URL不必定是用記最初提交的URL,由於可能用一些規則在此規則前已經對URL進行了處理。
mod_rewrite來講,!是個合法的模板前綴,表示的意思,這對描述不知足某種匹配條件的狀況很是方便,或用做最後一條默認規則。當使用!時,不能在模板中有分組的通配符,也不能作後向引用。
當匹配成功後,Substitution會被用來替換相應的匹配,它除了能夠是普通的字符串之外,還能夠包括:

1.  $N,引用RewriteRule模板中匹配的相關字串,N表示序號,N=0..9

2.  %N,引用最後一個RewriteCond模板中匹配的數據,N表示序號

3.  %{VARNAME},服務器變量

4.  ${mapname:key|default},映射函數調用

這些特殊內容的擴展,按上述順序進行。
一個URL的所有相關部分都會被Substitution替換,並且這個替換過程會一直持續到全部的規則都被執行完,除非明確地用L標誌中斷處理過程。
susbstitution」-」前綴時,表示不進行替換,只作匹配檢查。
利用RewriteRule,可定義含有請求串(Query String)URL,此時只需在Sustitution中加入一個?,表示此後的內容放入QUERY_STRING變量中。若是要清空一個QUERY_STRING變量,只須要以?結束Substitution串便可。
若是給一個Substitution增長一個http://thishost[:port]的前綴,則mod_rewrite會自動將此前綴去掉。所以,利用http://thisthost作一個無條件的重定向到本身,將難以奏效。要實現這種效果,必須使用R標誌。
Flags是可選參數,當有多個標誌同時出現時,彼此間以逗號分隔。

1.  'redirect|R [=code]' (強制重定向)
給當前的URI增長前綴http://thishost[:thisport]/, 從而生成一個新的URL,強制生成一個外部重定向(external redirection,指生的URL發送到客戶端,由客戶端再次以新的URL發出請求,雖然新URL仍指向當前的服務器). 若是沒有指定的code值,則HTTP應答以狀態值302 (MOVED TEMPORARILY),若是想使用300-400(不含400)間的其它值能夠經過在code的位置以相應的數字指定,也能夠用標誌名指定: temp (默認值), permanent, seeother.
注意,當使用這個標誌時,要確實substitution是個合法的URL,這個標誌只是在URL前增長http://thishost[:thisport]/前綴而已,重寫操做會繼續進行。若是要當即將新URL重定向,用L標誌來中重寫流程。

2.  'forbidden|F' (強制禁止訪問URL所指的資源)
當即返回狀態值403 (FORBIDDEN)的應答包。將這個標誌與合適的RewriteConds 聯合使用,能夠阻斷訪問某些URL

3.  'gone|G' (強制返回URL所指資源爲不存在(gone))
當即返回狀態值410 (GONE)的應答包。用這個標誌來標記URL所指的資源永久消失了.

4.  # 'proxy|P' (強制將當前URL送往代理模塊(proxy module)
這個標誌,強制將substitution看成一個發向代理模塊的請求,並當即將共送往代理模塊。所以,必須確保substitution串是一個合法的URI (, 典型的狀況是以http://hostname開頭),不然會從代理模塊獲得一個錯誤. 這個標誌,是ProxyPass指令的一個更強勁的實現,將遠程請求(remote stuff)映射到本地服務器的名字空間(namespace)中來。
注意,使用這個功能必須確保代理模塊已經編譯到Apache 服務器程序中了. 能夠用「httpd -l 」命令,來檢查輸出中是否含有mod_proxy.c來確認一下。若是沒有,而又須要使用這個功能,則須要從新編譯``httpd''程序並使用mod_proxy有效。

5.  'last|L' (最後一條規則)
停止重寫流程,再也不對當前URL施加更多的重寫規則。這至關於perllast命令或Cbreak命令。

6.  'next|N' (下一輪)
從新從第一條重寫規則開始執行重寫過程,新開的過程當中的URL不該當與最初的URL相同。 這至關於Perlnext命令或Ccontinue命令. 千萬當心不要產生死循環。

7.  # 'chain|C' (將當前的規則與其後續規則??(chained))
當規則匹配時,處理過程與沒有??綁同樣;若是規則不匹配,則??綁在一塊兒的後續規則也不在檢查和執行。

8.  'type|T=MIME-type' (強制MIME類型)
強制將目標文件的MIME-type爲某MIME類型。例如,這可用來模仿mod_alias模塊對某目錄的ScriptAlias指定,經過強制將該目錄下的全部文件的類型改成 「application/x-httpd-cgi」.

9.  'nosubreq|NS' (used only if no internal sub-request )
這個標誌強制重寫引擎跳過爲內部sub-request的重寫規則.例如,當mod_include試圖找到某一目錄下的默認文件時 (index.xxx)sub-requests 會在Apache內部發生. Sub-requests並不是老是有用的,在某些狀況下若是整個規則集施加到它上面,會產生錯誤。利用這個標誌可排除執行一些規則。

10. 'nocase|NC' (模板不區分大小寫)
這個標誌會使得模板匹配當前URL時忽略大小寫的差異。

11. 'qsappend|QSA' (追加請求串(query string))
這個標誌,強制重寫引擎爲Substitution的請求串追加一部分串,則不是替換掉原來的。藉助這個標誌,可使用一個重寫規則給請求串增長更多的數據。

12. 'noescape|NE' (不對輸出結果中的特殊字符進行轉義處理)
一般狀況下,mod_write的輸出結果中,特殊字符(如'%', '$', ';', )會轉義爲它們的16進制形式(如分別爲'%25', '%24', and '%3B')。這個標誌會禁止mod_rewrite對輸出結果進行此類操做。 這個標誌只能在 Apache 1.3.20及之後的版本中使用。

13. 'passthrough|PT' (經過下一個處理器)
這個標誌強制重寫引擎用filename字段的值來替換內部request_rec數據結構中uri字段的值。. 使用這個標誌,可使後續的其它URIto-filename轉換器的AliasScriptAliasRedirect等指令,也能正常處理RewriteRule指令的輸出結果。用一個小例子來講明它的語義:若是要用mod_rewrite的重寫引擎將/abc轉換爲/def,而後用mod_alas/def重寫爲ghi,則要:
RewriteRule ^/abc(.*) /def$1 [PT]
Alias /def /ghi
若是PT標誌被忽略,則mod_rewrite也能很好完成工做,若是., uri=/abc/...轉換爲filename=/def/... ,徹底符合一個URI-to-filename轉換器的動做。接下來 mod_alias 試圖作 URI-to-filename 轉換時就會出問題。
注意:若是要混合都含有URLto-filename轉換器的不一樣的模塊的指令,必須用這個標誌。最典型的例子是mod_aliasmod_rewrite的使用。

14. 'skip|S=num' (跳事後面的num個規則)
當前規則匹配時,強制重寫引擎跳事後續的num個規則。用這個能夠來模仿if-then-else結構:then子句的最後一條rule的標誌是skip=N,而Nelse子句的規則條數。

15. 'env|E=VAR:VAL' (設置環境變量)
設置名爲VAR的環境變量的值爲VAL,其中VAL中能夠含有正則式的後向引用($N%N)。這個標誌可使用屢次,以設置多個環境變量。這兒設置的變量,能夠在多種狀況下被引用,如在XSSICGI中。另外,也能夠在RewriteCond模板中以%{ENV:VAR}的形式被引用。

16.  


注意:必定不要忘記,在服務器範圍內的配置文件中,模板(pattern)用以匹配整個URL;而在目錄範圍內的配置文件中,目錄前綴老是被自動去掉後再進行模板匹配的,且在替換完成後自動再加上這個前綴。這個功能對不少種類的重寫是很是重要的,由於若是沒有去前綴,則要進行父目錄的匹配,而父目錄的信息並非總能獲得的。一個例外是,當substitution中有http://打頭時,則再也不自動增長前綴了,若是P標誌出現,則會強制轉向代理。
注意:若是要在某個目錄範圍內啓動重寫引擎,則須要在相應的目錄配置文件中設置「RewriteEngine on」,且目錄的「Options FollowSymLinks」必須設置。若是管理員因爲安全緣由沒有打開FollowSymLinks,則不能使用重寫引擎。

 

今天學習重寫規則的條件。

RewriteCond
Syntax: RewriteCond TestString CondPattern [flags]
RewriteCond指令定義一條規則條件。在一條RewriteRule指令前面可能會有一條或多條RewriteCond指令,只有當自身的模板(pattern)匹配成功且這些條件也知足時規則才被應用於當前URL處理。
TestString是一個字符串,除了包含普通的字符外,還能夠包括下列的可擴展結構:

1.  $N,RewriteRule後向引用,其中(0 <= N <= 9)
$N引用緊跟在RewriteCond後面的RewriteRule中模板中的括號中的模板在當前URL中匹配的數據。

2.  %N,RewriteCond後向引用,其中(0 <= N <= 9)
%N引用最後一個RewriteCond的模板中的括號中的模板在當前URL中匹配的數據。

3.  ${mapname:key|default},RewriteMap擴展.
具體參見RewriteMap

4.  %{ NAME_OF_VARIABLE } ,服務器變量。
變量的名字以下表(分類顯示)

HTTP headers:

connection & request:

server internals:

system stuff:

HTTP_USER_AGENT

REMOTE_ADDR

DOCUMENT_ROOT

TIME_YEAR

HTTP_REFERER

REMOTE_HOST

SERVER_ADMIN

TIME_MON

HTTP_COOKIE

REMOTE_USER

SERVER_NAME

TIME_DAY

HTTP_FORWARDED

REMOTE_IDENT

SERVER_ADDR

TIME_HOUR

HTTP_HOST

REQUEST_METHOD

SERVER_PORT

TIME_MIN

HTTP_PROXY_CONNECTION

SCRIPT_FILENAME

SERVER_PROTOCOL

TIME_SEC

HTTP_ACCEPT

PATH_INFO

SERVER_SOFTWARE

TIME_WDAY

 

QUERY_STRING

 

TIME

 

AUTH_TYPE

 

 

5.   

specials:

說明

API_VERSION

Apache與模塊間的接口的版本號

THE_REQUEST

客戶端發送到來的HTTP請求行的整行信息,不含其它的頭字段信息,如("GET /index.html HTTP/1.1")

REQUEST_URI

HTTP請求行中請求的資源

REQUEST_FILENAME

請求中對應的服務器本地文件系統中全路徑文件名

IS_SUBREQ

根據是否爲SubRequest,分別值爲」true」」false」

6.  
特別說明:

o   SCRIPT_FILENAMEREQUEST_FILENAME變量含有相同的值,也就是Apache服務器內部數據結構request_recfilename字段的值。第一個變量是一個CGI變量,而第二個則與REQUEST_URI(含有request_rec數據結構中uri字段的值)保持一致。

o   %{ENV:variable}中的variable能夠是任何環境變量的名字。對其值的查找,先經過Apache內部的數據結構,(如找不到)再在Apache服務器進程中經過getenv()查找。

o   %{HTTP:header}中的header能夠是任何HTTP MIME-header的名字,其值經過查找HTTP請求信息而得。

 

 

 

o   %{LA-U:variable} 用來引用後續API階段中定義的、當前還不知道的值,具體實現是經過執行一個基於URL的內部的sub-request來決定的variable的最終的值。例如,假如你想在服務器範圍內利用REMOTE_USER的值來完成重寫,但這個值是在驗證階段設置的,而驗證階段是在URL轉換階段的後面。從另外一方面講,因爲mod_rewrite在修補(fixup)API階段進行目錄範圍的重寫,而修補階段在驗證階段的後面,因此此時只要用%{REMOTE_USER}就能夠取得該值了。

o   %{LA-F:variable},執行一個基於文件名字(filename)的內部sub-request來決定variable的最終的值。大多數時間內,這和LA-U相同。

 


CondPattern是一個條件模板,也就是說,是一個擴展正則式(extended regular expression),用與跟TestString進行匹配。做爲一個標準的擴展正則式,CondPattern有如下補充:

1.  能夠在模板串前增長一個!前綴,以用表示不匹配模板。但並非全部的test均可以加!前綴。

2.  CondPattern中可使用如下特殊變量:

o   ' condPattern看成一個普通字符串,將它和TestString進行比較,當TestString 的字符小於CondPattern爲真.

o   '>CondPattern' (大於)
condPattern看成一個普通字符串,將它和TestString進行比較,當TestString 的字符大於CondPattern爲真.

o   '=CondPattern' (等於)
condPattern看成一個普通字符串,將它和TestString進行比較,當TestString CondPattern徹底相同時爲真.若是CondPattern只是 "" (兩個引號緊挨在一塊兒) 此時需TestString爲空字符串方爲真.

o   '-d' (是否爲目錄)
testString看成一個目錄名,檢查它是否存在以及是不是一個目錄.

o   '-f' (是不是regular file)
testString看成一個文件名,檢查它是否存在以及是不是一個regular文件.

o   '-s' (是否爲長度不爲的regular文件)
testString看成一個文件名,檢查它是否存在以及是不是一個長度大於的regular文件

o   '-l' (是否爲symbolic link)
testString看成一個文件名,檢查它是否存在以及是不是一個 symbolic link.

o   '-F' (經過subrequest來檢查某文件是否可訪問)
檢查TestString是不是一個合法的文件,並且經過服務器範圍內的當前設置的訪問控制進行訪問。這個檢查是經過一個內部subrequest完成的, 所以須要當心使用這個功能以下降服務器的性能。

o   '-U' (經過subrequest來檢查某個URL是否存在)
檢查TestString是不是一個合法的URL,並且經過服務器範圍內的當前設置的訪問控制進行訪問。這個檢查是經過一個內部subrequest完成的, 所以須要當心使用這個功能以下降服務器的性能。


[flags]是第三個參數,多個標誌之間用逗號分隔。

1.  'nocase|NC' (不區分大小寫)
在擴展後的TestStringCondPattern中,比較時不區分文本的大小寫。注意,這個標誌對文件系統和subrequest檢查沒有影響.

2.  'ornext|OR' (創建與下一個條件的或的關係)
默認的狀況下,二個條件之間是AND的關係,用這個標誌將關係改成OR。例如:


RewriteCond %{REMOTE_HOST} ^host1.* [OR]
RewriteCond %{REMOTE_HOST} ^host2.* [OR]
RewriteCond %{REMOTE_HOST} ^host3.*
RewriteRule ...


若是沒有[OR]標誌,須要寫三個條件/規則.


例子:根據客戶端瀏覽器的不一樣,返回不一樣的首頁面。

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]

 

 

今天學習重寫影射等內容。

RewriteMap
Syntax: RewriteMap MapName MapType:MapSource
RewriteMap指令定義一個重寫影射(Rewriting Map),在規則的substitution串中,經過影射函數(mapping-functions)來查找關鍵字(key),並用關鍵字對應的值來進行來行插入或替換操做。這個查找的對象,能夠是各類各樣的。
MapName是影射的名字,將用來經過下列的某種結構來爲substitution定義影射函數:
${ MapName : LookupKey }
${ MapName : LookupKey | DefaultValue }
當這些結構之一出現substitution串中時,重寫引擎會到mapname影射中查找lookupkey關鍵字,若是找到了就用返回的值(substvalue)來替換該結構,若是找不到就用defaultvalue來替換該結構,若是沒有defaultvalue,就用空串來替換。
MapType mapSource組合有如下幾種:

1.  標準的普通文本(Standard Plain Text)
MapType: txt, MapSource: Unix
文件系統中合法的帶有路徑的regular file
此種狀況下,MapSource文件是一個普通的ASCII文本文件,能夠含有空行、註釋行(以#打頭),及如下結構的鍵值對行(每一個鍵值對一行)。
MatchingKey SubstValue
例如:Mapsource文件叫/path/to/file/map.txt,其內容爲

##
## 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

 

2.  隨機的普通文本(Randomized Plain Text)
MapType: rnd, MapSource: Unix
文件系統中合法的帶有路徑的regular file

 

這種狀況與標準普通文本狀況很類似,差異只是在SubstValue的格式上:此時的SubstValue由一些用」|」分隔的值組成的串,這個或者的意思。當根據鍵值找到對應的SubstValue後,mod_rewrite藉助將此串分解爲一些候選項,而後隨機選擇一項做爲最終的SubstValue的值返回。這聽起來有點瘋狂或毫無用處,其實這是設計用來在反向代理(reverse proxy)的狀況下作負載均衡,用來查找服務器的名字。
例如:MapSource文件的名字爲/path/to/file/map.txt,內容以下:

##
## map.txt -- rewriting map
##
static www1|www2|www3|www4
dynamic www5|www6


在配置文件中定義的重寫影射爲:

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

 

3.  Hash File
MapType: dbm, MapSource: Unix
文件系統中合法的帶有路徑的regular file

 

這兒的Mapsource文件是一個二進制的NDBM格式的文件,含有與普通文本格式文件時相同的內容,爲了實現快速查找進行了優化處理後以一種特殊的格式來表達。 能夠用任何NDBM工具或者用下面的Perl腳本txt2dbm.pl來建立這種格式的文件:

#!/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 () {
next if (/^\s*#/ or /^\s*$/);
$DB{$1} = $2 if (/^\s*(\S+)\s+(\S+)/);
}

untie %DB;
close(TXT);


此腳本的使用方法以下:

$ perl txt2dbm.pl map.txt map.db

 

4.  Apache內部函數(Internal Function)
MapType: int, MapSource: Apache
內部函數

 

這時,MapSource是一個Apache內置函數,目前還不能建立本身的內部函數,只能使用Apache已經定義好的:

o   toupper
將鍵值轉換爲大寫

o   tolower
將鍵值轉換爲小寫

o   escape
將鍵值中的特殊字符轉換爲以16進製表示。

o   unescape
將鍵值中16進製表示的特殊字符轉換爲原來的樣子。

 

5.  外部重寫程序(External Rewriting Program
MapType: prg, MapSource: Unix
文件系統中合法的帶有路徑的regular file

 

這兒的MapSource是一個程序而不是一個影射文件。你可使用任何語言建立這個程序,但這個程序必須是可執行的(也就是說,要麼是二進制碼,要麼是首行帶有」#!/path/to/interpreter」格式的解釋器的可執行腳本)。

這個程序在Apache啓動時被運行,而後它就用它的標準輸入與標準輸出的文件句柄與重寫引擎通訊(暗指程序能無限時等待標準輸入,見下列)。對每一個影射函數的查找要求,它把其標準輸入中獲得的字符串(newline-terminated string?)做爲鍵值,而後經過標準輸出返回查找到的值,若是找不到相應的值,則返回以四字符的字符串」NULL「。下面一個簡單的例子,實現將鍵值做爲查找結果返回:

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


注意:

1.  ``Keep it simple, stupid'' (KISS),由於當規則執行時,一量這個外部程序掛起,整個Apache服務器就掛起了

2.  避免下述常見錯誤:緩存了標準輸出的I/O。這會致使死循環。這也是爲何上例中有``$|=1''這麼一行的緣由

3.  RewriteLock指令定義一個lockfile,以同步與外部程序的通訊。默認狀況下並無這樣的同步

 


RewriteMap能夠出現不僅一次。每一個影射函數用RewriteMap來聲明它的影射文件. While you cannot declare a map in per-directory context it is of course possible to use this map in per-directory context.(?)對普通文本和DBM格式的文件,其鍵值被緩存在Apache內核中,直到影射文件的mtime 變化了或Apache重啓動了。此時,能夠將規則中的影射函數用於每一個請求。
RewriteBase
Syntax: RewriteBase URL-path
RewriteBase明確地指出目錄範圍內的重寫結果的baseURL.RewriteRule指令能夠用在目錄範圍內的配置文件裏(.htaccess)。在目錄範圍的重寫實施時,由本地路徑信息構成的前綴已經被去掉,重寫規則只對剩餘的部分進行處理。處理結束後,被去掉的路徑信息要自動加上,由於當對一個URL進行替換後,從新引擎須要將它從新插入到服務器的處理流程中去。若是服務器端的URL與文件的物理路徑有直接有關係,則每當在.htacess文中定義重寫規則時都須要用RewriteBaseURL-path
雜項Environment Variables
mod_rewrite還維護着兩個非標準的CGI/SSI環境變量,名爲SCRIPT_URL SCRIPT_URI,存放着當前資源的邏輯web視圖(logical Web-view)。標準的CGI/SSI變量SCRIPT_NAME SCRIPT_FILENAME中存放着當前資源的物理系統視圖(physical System-view)。請看例子:

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

RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]

/~user重寫爲/u/user的形式

 

RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]

/u/user末尾漏掉的/補上

 

 

 

規範化HostName

RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]

域名不合格

 

RewriteCond %{HTTP_HOST} !^$

不空

 

RewriteCond %{SERVER_PORT} !^80$

不是80端口

 

RewriteRule ^/(.*) http://fully.qualified.domain.name:%{SERVER_PORT}/$1 [L,R]

重寫

 

RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]

 

 

RewriteCond %{HTTP_HOST} !^$

 

 

RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]

 

 

 

 

URL根目錄轉移

RewriteEngine on

 

 

RewriteRule ^/$ /e/www/ [R]

/移到/e/www/

 

 

 

末尾目錄補斜線

RewriteEngine on

 

(目錄範圍內)

RewriteBase /~quux/

 

 

RewriteRule ^foo$ foo/ [R]

/~quux/foo是一個目錄,補/

 

 

 

 

RewriteEngine on

 

 

RewriteBase /~quux/

 

 

RewriteCond %{REQUEST_FILENAME} -d

若是請文件名是個目錄

 

RewriteRule ^(.+[^/])$ $1/ [R]

URL末尾不是斜線時補上

 

 

 

Web集羣

RewriteEngine on

 

 

RewriteMap user-to-host txt:/path/to/map.user-to-host

用戶-服務器映射

 

RewriteMap group-to-host txt:/path/to/map.group-to-host

組-服務器映射

 

RewriteMap entity-to-host txt:/path/to/map.entity-to-host

實體-服務器映射

 

RewriteRule ^/u/([^/]+)/?(.*) http://${user-to-host:$1|server0}/u/$1/$2

用戶均衡

 

RewriteRule ^/g/([^/]+)/?(.*) http://${group-to-host:$1|server0}/g/$1/$2

組均衡

 

RewriteRule ^/e/([^/]+)/?(.*) http://${entity-to-host:$1|server0}/e/$1/$2

實體均衡

 

RewriteRule ^/([uge])/([^/]+)/?$ /$1/$2/.www/

 

 

RewriteRule ^/([uge])/([^/]+)/([^.]+.+) /$1/$2/.www/$3\

 

 

 

 

URL根目錄搬遷

RewriteEngine on

 

 

RewriteRule ^/~(.+) http://newserver/~$1 [R,L]

到其它服務器

 

 

 

所用戶名首字母分

RewriteEngine on

 

 

RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3

內一層括號爲$2

 

 

 

NCSA imagemap

RewriteEngine on

 

植爲mod_imap

RewriteRule ^/cgi-bin/imagemap(.*) $1 [PT]

 

 

 

 

多目錄查找資源

RewriteEngine on

 

 

# first try to find it in custom/...

 

 

RewriteCond /your/docroot/dir1/%{REQUEST_FILENAME} -f

 

 

RewriteRule ^(.+) /your/docroot/dir1/$1 [L]

 

 

# second try to find it in pub/...

 

 

RewriteCond /your/docroot/dir2/%{REQUEST_FILENAME} -f

 

 

RewriteRule ^(.+) /your/docroot/dir2/$1 [L]

 

 

# else go on for other Alias or ScriptAlias directives,

 

 

RewriteRule ^(.+) - [PT]

 

 

 

 

URL設置環境變量

RewriteEngine on

 

 

RewriteRule ^(.*)/S=([^/]+)/(.*) $1/$3 [E=STATUS:$2]

 

 

 

 

虛擬主機

RewriteEngine on

 

 

RewriteCond %{HTTP_HOST} ^www\.[^.]+\.host\.com$

基於用戶名

 

RewriteRule ^(.+) %{HTTP_HOST}$1 [C]

 

 

RewriteRule ^www\.([^.]+)\.host\.com(.*) /home/$1$2

 

 

 

 

內外人有別

RewriteEngine on

 

 

RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$

基於遠程主機

 

RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]

 

 

 

 

錯誤重定向

RewriteEngine on

 

 

RewriteCond /your/docroot/%{REQUEST_FILENAME} !-f

不是regular文件

 

RewriteRule ^(.+) http://webserverB.dom/$1

 

 

 

 

程序處理特殊協議

RewriteRule ^xredirect:(.+) /path/to/nph-xredirect.cgi/$1 \

Xredirect協議

 

[T=application/x-httpd-cgi,L]

 

 

 

 

最近鏡像下載

RewriteEngine on

 

 

RewriteMap multiplex txt:/path/to/map.cxan

頂級域名與最近ftp服務器映射

 

RewriteRule ^/CxAN/(.*) %{REMOTE_HOST}::$1 [C]

 

 

RewriteRule ^.+\.([a-zA-Z]+)::(.*)$ ${multiplex:$1|ftp.default.dom}$2 [R,L]

據頂級域名不一樣提供不一樣的FTP服務器

 

 

 

基於時間重寫

RewriteEngine on

 

 

RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700

 

 

RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900

 

 

RewriteRule ^foo\.html$ foo.day.html

白天爲遲早7點間

 

RewriteRule ^foo\.html$ foo.night.html

其他爲夜間

 

 

 

向前兼容擴展名

RewriteEngine on

 

 

RewriteBase /~quux/

 

 

# parse out basename, but remember the fact

 

 

RewriteRule ^(.*)\.html$ $1 [C,E=WasHTML:yes]

 

 

# rewrite to document.phtml if exists

 

 

RewriteCond %{REQUEST_FILENAME}.phtml -f

若是存在$1.phtml則重寫

 

RewriteRule ^(.*)$ $1.phtml [S=1]

 

 

# else reverse the previous basename cutout

 

 

RewriteCond %{ENV:WasHTML} ^yes$

若是不存在$1.phtml,則保持不變

 

RewriteRule ^(.*)$ $1.html

 

 

 

 

文件更名(目錄級)

RewriteEngine on

內部重寫

 

RewriteBase /~quux/

 

 

RewriteRule ^foo\.html$ bar.html

 

 

 

 

 

RewriteEngine on

重定向由客戶端再次提交

 

RewriteBase /~quux/

 

 

RewriteRule ^foo\.html$ bar.html [R]

 

 

 

 

據瀏覽器類型重寫

RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*

 

 

RewriteRule ^foo\.html$ foo.NS.html [L]

 

 

RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]

 

 

RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*

 

 

RewriteRule ^foo\.html$ foo.20.html [L]

 

 

RewriteRule ^foo\.html$ foo.32.html [L]

 

 

 

 

動態鏡像遠程資源

RewriteEngine on

 

 

RewriteBase /~quux/

 

 

RewriteRule ^hotsheet/(.*)$ http://www.tstimpreso.com/hotsheet/$1 [P]

利用了代理模塊

 

 

 

 

RewriteEngine on

 

 

RewriteBase /~quux/

 

 

RewriteRule ^usa-news\.html$ http://www.quux-corp.com/news/index.html [P]

 

 

 

 

反向動態鏡像

RewriteEngine on

 

 

RewriteCond /mirror/of/remotesite/$1 -U

 

 

RewriteRule ^http://www\.remotesite\.com/(.*)$ /mirror/of/remotesite/$1

 

 

 

 

負載均衡

RewriteEngine on

利用代理實現round-robin效果

 

RewriteMap lb prg:/path/to/lb.pl

 

 

RewriteRule ^/(.+)$ ${lb:$1} [P,L]

 

 

 

 

 

#!/path/to/perl

 

 

$| = 1;

 

 

$name = "www"; # the hostname base

 

 

$first = 1; # the first server (not 0 here, because 0 is myself)

 

 

$last = 5; # the last server in the round-robin

 

 

$domain = "foo.dom"; # the domainname

 

 

$cnt = 0;

 

 

while (<STDIN>) {

 

 

$cnt = (($cnt+1) % ($last+1-$first));

 

 

$server = sprintf("%s%d.%s", $name, $cnt+$first, $domain);

 

 

print "http://$server/$_";

 

 

}

 

 

##EOF##

 

 

 

 

靜態頁面變腳本

RewriteEngine on

 

 

RewriteBase /~quux/

 

 

RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]

 

 

 

 

阻擊機器人

RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*

 

 

RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$

 

 

RewriteRule ^/~quux/foo/arc/.+ - [F]

 

 

 

 

阻止盜連你的圖片

RewriteCond %{HTTP_REFERER} !^$

 

 

RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]

本身的鏈接可不能被阻止

 

RewriteRule .*\.gif$ - [F]

 

 

 

 

 

RewriteCond %{HTTP_REFERER} !^$

 

 

RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$

 

 

RewriteRule ^inlined-in-foo\.gif$ - [F]

 

 

 

 

拒絕某些主機訪問

RewriteEngine on

 

 

RewriteMap hosts-deny txt:/path/to/hosts.deny

 

 

RewriteCond ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND [OR]

 

 

RewriteCond ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND

 

 

RewriteRule ^/.* - [F]

 

 

 

 

用戶受權

RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^friend1@client1.quux-corp\.com$

 

 

RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^friend2@client2.quux-corp\.com$

 

 

RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^friend3@client3.quux-corp\.com$

 

 

RewriteRule ^/~quux/only-for-friends/ - [F]

 

 

 

 

外部重寫程序模板

RewriteEngine on

 

 

RewriteMap quux-map prg:/path/to/map.quux.pl

 

 

RewriteRule ^/~quux/(.*)$ /~quux/${quux-map:$1}

 

 

 

 

 

#!/path/to/perl

 

 

$| = 1;

 

 

while (<>) {

 

 

s|^foo/|bar/|;

 

 

print $_;

 

 

}

 

 

 

 

搜索引擎友好

RewriteRule ^/products$ /content.php

 

 

RewriteRule ^/products/([0-9]+)$ /content.php?id=$1

 

 

RewriteRule ^/products/([0-9]+),([ad]*),([0-9]{0,3}),([0-9]*),([0-9]*$) /marso/content.php?id=$1&sort=$2&order=$3&start=$4

 

 

 

狗尾續貂一把,把我在實際中用的apache+mod_jk+tomcat+mod_rewrite來重寫含有.jspURL設置帖出來,其實就是簡單地把前面學的用了一下,供參考。

假定你已經利用mod_jkapachetomcat協同起來工做了,而且已經開發了一個web應用叫mywebapp。對httpd.conf改動以下:

1.  兩個模塊的加載順序


...
LoadModule rewrite_module modules/mod_rewrite.so
...
LoadModule jk_module modules/mod_jk.so
...
AddModule mod_jk.c
....
AddModule mod_rewrite.c
....

 

2.  兩個模塊的設置順序


...
<IfModule mod_jk.c>
...
JkWorkersFile "/path/to/workers.properties"
JkLogFile "/path/to/mod_jk.log"
JkLogLevel info
...
JkMount /*.jsp ajp13
</IfModule>
...
<VirtualHost *>
...
ServerName hedong.3322.org
...
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteMap id2jsp txt:/path/to/id2jsp.txt #jsp
文件名編碼表
RewriteMap id2db txt:/path/to/id2db.txt #
數據庫名字編碼表
RewriteRule ^/mywebapp/([0-9]*)/([0-9]*),([0-9]*)\.html ${id2jsp:$1}\?dbname=${id2db:$2}&r=$3 [PT] #
參數r表示記錄IDPT容許mod_jk繼續處理請求URL
RewriteRule ^/mywebapp$ /mywebapp/ [R] #
被全目錄名後被省略的/
RewriteRule ^/mywebapp/$ /mywebapp/index\.jsp [PT] #PT
容許mod_jk繼續處理請求URL
....
</IfModule>
JkMount /mywebapp ajp13
JkMount /mywebapp/* ajp13
....
</VirtualHost>

 

3.  一點感想
當用mod_rewrite在服務器範圍內對請求URL進行重寫時,若是涉及到URL中目錄層次的變化(如原本是一層目錄/a/page.html,如今被寫成/jsps/part1/page.jsp)時,要當心,由於:HTML/jsp頁面中不少連接是相對連接,尤爲是圖片連接尤其常見, 即如../images/1.jpg等。
當你重寫了URL的目錄層次時,頁面中的相對連接不受重寫的影響,而致出現顯示問題。
接着上面的例子,假定/jsps/part1/page.jsp中有一個連接爲../images/1.jpg,並且/jsps/images/1.jpg確實存在,當不用mod_rewrite重寫時,/jsps/part1/page.jsp顯示正常。而重寫之後,page.jsp能運行,而1.jpgURL變成了/images/1.jpg了,雖然你在重寫是改動了目錄,此1.jpgURL仍是相對於/a/的。

相關文章
相關標籤/搜索