這個模塊使用一個基於正則表達式解析器開發的重寫引擎,根據web管理員定義的規則來實時(on the fly)重寫請求URL。它支持任意數目的重寫規則,以及附加到一條規則上的任意數目的規則條件,從而提供了一套非常靈活和功能強大的URL處理機制。 URL處理操作的實施與否,依賴於各種各樣的條件檢查,如檢查服務器變量、環境變量、HTTP頭字段、時間戳的值,甚至外部數據庫的檢索結果。這個模塊可 以在服務器範圍內(http.conf)、目錄範圍內(.htaccess)或請求串(query-string)的一部分處理有關的URL。重寫的結果
URL,可以指向一個站內的處理程序、指向站外的重定向或者一個站內的代理。與靈活和功能強大相隨的是設置的複雜,別指望一天內弄明白整個模塊。(所以, 這個學習筆記也分了幾部分:)
內部處理過程
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能進行URL到URL、URL到文件 名字甚至文件名字到文件名字的轉換,API(1.x)目前提供了一個URL_to_filename轉換。在Apache2.0中,這兩個鉤子會被加進 去,整個過程會更加清晰。一個事實必須清楚的記得:Apache在URL_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).如圖一所示:
正如所看到的,首先URL會與每條規則的模板(pattern)比較,當匹配失敗時,立即停止對當前規則的處理進入下一條規則。當匹配成功 時,mod_rewrite尋找相關的規則條件。如果找不到相關的條件,則直接執行規則中定義的替換,然後回到規則遍歷的過程。如果找到了相關的條件,則 啓動一個內部循環,依次檢查各個條件。對於檢查,我們不是拿一個模板來匹配當前的URL,而是先創建一個TestString串,將串內的變量、後向引用 (bakc-reference)、查詢結果(map lookups)等展開,然後用這個TestString和條件式中的CondPattern進行匹配,如果匹配失敗,則整個條件集且這個規則都不再執
行,重要回到規則遍歷中;如果匹配成功,則檢查下一個條件,如果所有的條件都滿足,則執行規則中定義的替換動作。
特殊字符的轉義
既然基於正則式,則當然會有特殊字符的問題。在1.3.20版本的Apache中,通過在特殊字符前加一個“\”來將TestString或Sustitution串的特殊字符轉義。
正則式的後向引用
有一點需要記住:一旦在模板(pattern)或條件模板(CondPattern)中使用了括號,則後向引用已經自動產生了,你可以在Sustitution或TestString中通過$N或%N來引用相關的值。如圖,描述了後向引用的值可以傳到的位置。
配置指令(Configuration Directives)
指令 | 語法 | 默認值 | 說明 | 備註 |
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 | 設置日誌級別 | 0表示沒有,2以上用於debug,9及以上表示全部信息 |
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 | 定義重寫規則 | 具體說明參見文檔 |
參考資料:
http://httpd.apache.org/docs/mod/mod_rewrite.html
Apache的Mod_rewrite學習(二)
今天學習重寫規則的語法。
RewriteRule
Syntax: RewriteRule Pattern Substitution [flags]
一條RewriteRule指令,定義一條重寫規則,規則間的順序非常重要。對Apache1.2及以後的版本,模板(pattern)是一個 POSIX正則式,用以匹配當前的URL。當前的URL不一定是用記最初提交的URL,因爲可能用一些規則在此規則前已經對URL進行了處理。
對mod_rewrite來說,!是個合法的模板前綴,表示“非”的意思,這對描述“不滿足某種匹配條件”的情況非常方便,或用作最後一條默認規則。當使用!時,不能在模板中有分組的通配符,也不能做後向引用。
當匹配成功後,Substitution會被用來替換相應的匹配,它除了可以是普通的字符串以外,還可以包括:
- $N,引用RewriteRule模板中匹配的相關字串,N表示序號,N=0..9
- %N,引用最後一個RewriteCond模板中匹配的數據,N表示序號
- %{VARNAME},服務器變量
- ${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是可選參數,當有多個標誌同時出現時,彼此間以逗號分隔。
-
'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標誌來中重寫流程。 -
'forbidden|F' (強制禁止訪問URL所指的資源)
立即返回狀態值403 (FORBIDDEN)的應答包。將這個標誌與合適的RewriteConds 聯合使用,可以阻斷訪問某些URL。 -
'gone|G' (強制返回URL所指資源爲不存在(gone))
立即返回狀態值410 (GONE)的應答包。用這個標誌來標記URL所指的資源永久消失了. -
# 'proxy|P' (強制將當前URL送往代理模塊(proxy module))
這個標誌,強制將substitution當作一個發向代理模塊的請求,並立即將共送往代理模塊。因此,必須確保substitution串是一個合法 的URI (如, 典型的情況是以http://hostname開頭),否則會從代理模塊得到一個錯誤. 這個標誌,是ProxyPass指令的一個更強勁的實現,將遠程請求(remote stuff)映射到本地服務器的名字空間(namespace)中來。
注意,使用這個功能必須確保代理模塊已經編譯到Apache 服務器程序中了. 可以用“httpd -l ”命令,來檢查輸出中是否含有mod_proxy.c來確認一下。如果沒有,而又需要使用這個功能,則需要重新編譯``httpd''程序並使用 mod_proxy有效。 -
'last|L' (最後一條規則)
中止重寫流程,不再對當前URL施加更多的重寫規則。這相當於perl的last命令或C的break命令。 -
'next|N' (下一輪)
重新從第一條重寫規則開始執行重寫過程,新開的過程中的URL不應當與最初的URL相同。 這相當於Perl的next命令或C的continue命令. 千萬小心不要產生死循環。 -
# 'chain|C' (將當前的規則與其後續規則??綁(chained))
當規則匹配時,處理過程與沒有??綁一樣;如果規則不匹配,則??綁在一起的後續規則也不在檢查和執行。 -
'type|T=MIME-type' (強制MIME類型)
強制將目標文件的MIME-type爲某MIME類型。例如,這可用來模仿mod_alias模塊對某目錄的ScriptAlias指定,通過強制將該目錄下的所有文件的類型改爲 “application/x-httpd-cgi”. -
'nosubreq|NS' (used only if no internal sub-request )
這個標誌強制重寫引擎跳過爲內部sub-request的重寫規則.例如,當mod_include試圖找到某一目錄下的默認文件時 (index.xxx),sub-requests 會在Apache內部發生. Sub-requests並非總是有用的,在某些情況下如果整個規則集施加到它上面,會產生錯誤。利用這個標誌可排除執行一些規則。 -
'nocase|NC' (模板不區分大小寫)
這個標誌會使得模板匹配當前URL時忽略大小寫的差別。 -
'qsappend|QSA' (追加請求串(query string))
這個標誌,強制重寫引擎爲Substitution的請求串追加一部分串,則不是替換掉原來的。藉助這個標誌,可以使用一個重寫規則給請求串增加更多的數據。 -
'noescape|NE' (不對輸出結果中的特殊字符進行轉義處理)
通常情況下,mod_write的輸出結果中,特殊字符(如'%', '$', ';', 等)會轉義爲它們的16進制形式(如分別爲'%25', '%24', and '%3B')。這個標誌會禁止mod_rewrite對輸出結果進行此類操作。 這個標誌只能在 Apache 1.3.20及以後的版本中使用。 -
'passthrough|PT' (通過下一個處理器)
這個標誌 強制重寫引擎用filename字段的值來替換內部request_rec數據結構中uri字段的值。. 使用這個標誌,可以使後續的其它URI-to-filename轉換器的Alias、ScriptAlias、Redirect等指令,也能正常處理 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 轉換時就會出問題。
注意:如果要混合都含有URL-to-filename轉換器的不同的模塊的指令,必須用這個標誌。最典型的例子是mod_alias和mod_rewrite的使用。 -
'skip|S=num' (跳過後面的num個規則)
當前規則匹配時,強制重寫引擎跳過後續的num個規則。用這個可以來模仿if-then-else結構:then子句的最後一條rule的標誌是skip=N,而N是else子句的規則條數。 -
'env|E=VAR:VAL' (設置環境變量)
設置名爲VAR的環境變量的值爲VAL,其中VAL中可以含有正則式的後向引用($N或%N)。這個標誌可以使用多次,以設置多個環境變量。這兒設置的 變量,可以在多種情況下被引用,如在XSSI或CGI中。另外,也可以在RewriteCond模板中以%{ENV:VAR}的形式被引用。
注意:一定不要忘記,在服務器範圍內的配置文件中,模板(pattern)用以匹配整個URL;而在目錄範圍內的配置文件中,目錄前綴總是 被自動去掉後再進行模板匹配的,且在替換完成後自動再加上這個前綴。這個功能對很多種類的重寫是非常重要的,因爲如果沒有去前綴,則要進行父目錄的匹配, 而父目錄的信息並不是總能得到的。一個例外是,當substitution中有http://打頭時,則不再自動增加前綴了,如果P標誌出現,則會強制轉 向代理。
注意:如果要在某個目錄範圍內啓動重寫引擎,則需要在相應的目錄配置文件中設置“RewriteEngine on”,且目錄的“Options FollowSymLinks”必須設置。如果管理員由於安全原因沒有打開FollowSymLinks,則不能使用重寫引擎。
Apache的Mod_rewrite學習(三)
今天學習重寫規則的條件。
RewriteCond
Syntax: RewriteCond TestString CondPattern [flags]
RewriteCond指令定義一條規則條件。在一條RewriteRule指令前面可能會有一條或多條RewriteCond指令,只有當自身的模板(pattern)匹配成功且這些條件也滿足時規則才被應用於當前URL處理。
TestString是一個字符串,除了包含普通的字符外,還可以包括下列的可擴展結構:
-
$N,RewriteRule後向引用,其中(0 <= N <= 9)
$N引用緊跟在RewriteCond後面的RewriteRule中模板中的括號中的模板在當前URL中匹配的數據。 -
%N,RewriteCond後向引用,其中(0 <= N <= 9)
%N引用最後一個RewriteCond的模板中的括號中的模板在當前URL中匹配的數據。 -
${mapname:key|default},RewriteMap擴展.
具體參見RewriteMap -
%{ 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 specials: 說明 API_VERSION Apache與模塊間的接口的版本號 THE_REQUEST 客戶端發送到來的HTTP請求行的整行信息,不含其它的頭字段信息,如("GET /index.html HTTP/1.1") REQUEST_URI HTTP請求行中請求的資源 REQUEST_FILENAME 請求中對應的服務器本地文件系統中全路徑文件名 IS_SUBREQ 根據是否爲SubRequest,分別值爲”true”或”false”
特別說明:-
SCRIPT_FILENAME 和REQUEST_FILENAME變量含有相同的值,也就是Apache服務器內部數據結構request_rec的filename字段的值。第一個 變量是一個CGI變量,而第二個則與REQUEST_URI(含有request_rec數據結構中uri字段的值)保持一致。
-
%{ENV:variable}中的variable可以是任何環境變量的名字。對其值的查找,先通過Apache內部的數據結構,(如找不到)再在Apache服務器進程中通過getenv()查找。
- %{HTTP:header}中的header可以是任何HTTP MIME-header的名字,其值通過查找HTTP請求信息而得。
-
%{LA-U:variable} 用來引用後續API階段中定義的、當前還不知道的值,具體實現是通過執行一個基於URL的內部的sub-request來決定的variable的最終的 值。例如,假如你想在服務器範圍內利用REMOTE_USER的值來完成重寫,但這個值是在驗證階段設置的,而驗證階段是在URL轉換階段的後面。從另一 方面講,由於mod_rewrite在修補(fixup)API階段進行目錄範圍的重寫,而修補階段在驗證階段的後面,所以此時只要用% {REMOTE_USER}就可以取得該值了。
- %{LA-F:variable},執行一個基於文件名字(filename)的內部sub-request來決定variable的最終的值。大多數時間內,這和LA-U相同。
-
SCRIPT_FILENAME 和REQUEST_FILENAME變量含有相同的值,也就是Apache服務器內部數據結構request_rec的filename字段的值。第一個 變量是一個CGI變量,而第二個則與REQUEST_URI(含有request_rec數據結構中uri字段的值)保持一致。
CondPattern是一個條件模板,也就是說,是一個擴展正則式(extended regular expression),用與跟TestString進行匹配。作爲一個標準的擴展正則式,CondPattern有以下補充:
-
可以在模板串前增加一個!前綴,以用表示不匹配模板。但並不是所有的test都可以加!前綴。
-
CondPattern中可以使用以下特殊變量:
-
' 將condPattern當作一個普通字符串,將它和TestString進行比較,當TestString 的字符小於CondPattern爲真.
-
'>CondPattern' (大於)
將condPattern當作一個普通字符串,將它和TestString進行比較,當TestString 的字符大於CondPattern爲真. -
'=CondPattern' (等於)
將condPattern當作一個普通字符串,將它和TestString進行比較,當TestString 與CondPattern完全相同時爲真.如果CondPattern只是 "" (兩個引號緊挨在一起) 此時需TestString 爲空字符串方爲真. -
'-d' (是否爲目錄)
將testString當作一個目錄名,檢查它是否存在以及是否是一個目錄. -
'-f' (是否是regular file)
將testString當作一個文件名,檢查它是否存在以及是否是一個regular文件. -
'-s' (是否爲長度不爲0的regular文件)
將testString當作一個文件名,檢查它是否存在以及是否是一個長度大於0的regular文件 -
'-l' (是否爲symbolic link)
將testString當作一個文件名,檢查它是否存在以及是否是一個 symbolic link. -
'-F' (通過subrequest來檢查某文件是否可訪問)
檢查TestString是否是一個合法的文件,而且通過服務器範圍內的當前設置的訪問控制進行訪問。這個檢查是通過一個內部subrequest完成的, 因此需要小心使用這個功能以降低服務器的性能。 -
'-U' (通過subrequest來檢查某個URL是否存在)
檢查TestString是否是一個合法的URL,而且通過服務器範圍內的當前設置的訪問控制進行訪問。這個檢查是通過一個內部subrequest完成的, 因此需要小心使用這個功能以降低服務器的性能。
-
' 將condPattern當作一個普通字符串,將它和TestString進行比較,當TestString 的字符小於CondPattern爲真.
[flags]是第三個參數,多個標誌之間用逗號分隔。
-
'nocase|NC' (不區分大小寫)
在擴展後的TestString和CondPattern中,比較時不區分文本的大小寫。注意,這個標誌對文件系統和subrequest檢查沒有影響. -
'ornext|OR' (建立與下一個條件的或的關係)
默認的情況下,二個條件之間是AND的關係,用這個標誌將關係改爲OR。例如:
RewriteCond %{REMOTE_HOST} ^host1.* [OR]
RewriteCond %{REMOTE_HOST} ^host2.* [OR]
RewriteCond %{REMOTE_HOST} ^host3.*
RewriteRule ...
如果沒有[OR]標誌,需要寫三個條件/規則.
例子:根據客戶端瀏覽器的不同,返回不同的首頁面。
RewriteRule ^/$ /homepage.max.html [L]
RewriteCond %{HTTP_USER_AGENT} ^Lynx.*
RewriteRule ^/$ /homepage.min.html [L]
RewriteRule ^/$ /homepage.std.html [L]
Apache的Mod_rewrite學習(四)
今天學習重寫影射等內容。
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組合有以下幾種:
-
標準的普通文本(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 -
隨機的普通文本(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 -
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 -
Apache內部函數(Internal Function)
MapType: int, MapSource: Apache內部函數這時,MapSource是一個Apache內置函數,目前還不能創建自己的內部函數,只能使用Apache已經定義好的:
-
toupper
將鍵值轉換爲大寫 -
tolower
將鍵值轉換爲小寫 -
escape
將鍵值中的特殊字符轉換爲以16進製表示。 -
unescape
將鍵值中16進製表示的特殊字符轉換爲原來的樣子。
-
toupper
-
外部重寫程序(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 $_;
}
注意:-
``Keep it simple, stupid'' (KISS),因爲當規則執行時,一量這個外部程序掛起,整個Apache服務器就掛起了
-
避免下述常見錯誤:緩存了標準輸出的I/O。這會導致死循環。這也是爲什麼上例中有``$|=1''這麼一行的原因
- 用RewriteLock指令定義一個lockfile,以同步與外部程序的通信。默認情況下並沒有這樣的同步
-
``Keep it simple, stupid'' (KISS),因爲當規則執行時,一量這個外部程序掛起,整個Apache服務器就掛起了
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文中定義重寫規則時都需要用RewriteBase指URL-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_FILENAME=/u/rse/.www/index.html
SCRIPT_URL=/u/rse/
SCRIPT_URI=http://en1.engelschall.com/u/rse/
Apache的Mod_rewrite學習(五)
今天主要列出一些例子。由於有些例子是針對特殊路徑或特別情況的,列出供大家在思路上參考。因爲它們就是些例子。
目標 | 重寫設置 | 說明 |
規範化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} !^[email protected]\.com$ | |
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^[email protected]\.com$ | ||
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^[email protected]\.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 |
參考文獻:
URL Rewriting Guide
http://httpd.apache.org/docs/misc/rewriteguide.html
mod_rewrite: A Beginner's Guide to URL Rewriting
http://www.sitepoint.com/article/910
Apache的Mod_rewrite學習(六)
狗尾續貂一把,把我在實際中用的apache+mod_jk+tomcat+mod_rewrite來重寫含有.jsp的URL設置帖出來,其實就是簡單地把前面學的用了一下,供參考。
假定你已經利用mod_jk把apache和tomcat協同起來工作了,並且已經開發了一個web應用叫mywebapp。對httpd.conf改動如下:
-
兩個模塊的加載順序
...
LoadModule rewrite_module modules/mod_rewrite.so
...
LoadModule jk_module modules/mod_jk.so
...
AddModule mod_jk.c
....
AddModule mod_rewrite.c
.... -
兩個模塊的設置順序
...
<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表示記錄ID,PT允許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> -
一點感想
當用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.jpg 的URL變成了/images/1.jpg了,雖然你在重寫是改動了目錄,此1.jpg的URL還是相對於/a/的。
版權聲明:可以任意轉載,轉載時請務必以超鏈接形式標明文章原始出處和作者信息及本聲明
http://www.chedong.com/tech/google_url.html
關鍵詞:"url rewrite" mod_rewrite isapi rewrite path_info iis "search engine friendly"
內容摘要:不得不承認,將動態網頁鏈接rewriting成靜態鏈接是最保險和穩定的面向搜索引擎優化方式
此外隨着互聯網上的內容以驚人速度的增長也越來越突出了搜索引擎的重要性,如果網站想更好地被搜索引擎收錄,網站設計除了面向用戶友好(User Friendly)外,搜索引擎友好(Search
Engine Friendly)的設計也是非常重要的。進入搜索引擎的頁面內容越多,則被用戶用不同的關鍵詞找到的機率越大。在Google的算法調查一
文中提到一個站點被Google索引頁面的數量其實對PageRank也是有一定影響的。由於Google 突出的是整個網絡中相對靜態的部分(動態網頁索引量比較小),鏈接地址相對固定的靜態網頁比較適合被Google索引(怪不得很多大網站的郵件列表歸檔和 BLOG按日期歸檔的文檔很容被搜的到),因此很多關於面向搜索引擎 URL設計優化(URI Pretty)的文章中提到了很多利用一定機制將動態網頁參數變成像靜態網頁的形式:
比如可以將:
http://phpunixman.sourceforge.net/index.php?mode=man¶meter=ls
變成:
http://phpunixman.sourceforge.net/index.php/man/ls
實現方式主要有2種:
把URI地址用作參數傳遞:URL REWRITE
最簡單的是基於各種WEB服務器中的URL重寫轉向(Rewrite)模塊的URL轉換:
這樣幾乎可以不修改程序的實現將 news.asp?id=234 這樣的鏈接映射成 news/234.html,從外面看上去和靜態鏈接一樣。Apache服務器上有一個模塊(非缺省):mod_rewrite:URL REWRITE功能之強大足夠寫上一本書。
當我需要將將news.asp?id=234的映射成news/234.html時,只需設置:
RewriteRule /news/(\d+)\.html /news\.asp\?id=$1 [N,I]
這樣就把 /news/234.html 這樣的請求映射成了 /news.asp?id=234
當有對/news/234.html的請求時:web服務器會把實際請求轉發給/news.asp?id=234
而在IIS也有相應的REWRITE模塊:比如ISAPI REWRITE和IIS REWRITE,語法都是基於正則表達式,因此配置幾乎和apache的mod_rewrite是相同的:
比對於某一個簡單應用可以是:
RewriteRule /news/(\d+)\.html /news/news\.php\?id=$1 [N,I]
這樣就把 http://www.chedong.com/news/234.html 映射到了 http://www.chedong.com/news/news.php?id=234
一個更通用的能夠將所有的動態頁面進行參數映射的表達式是:
把 http://www.myhost.com/foo.php?a=A&b=B&c=C
表現成 http://www.myhost.com/foo.php/a/A/b/B/c/C。
RewriteRule (.*?\.php)(\?[^/]*)?/([^/]*)/([^/]*)(.+?)?$1(?2$2&:\?)$3=$4?5$5: [N,I]
以下是針對phpBB的一個Apache mod_rewrite配置樣例:
RewriteEngine On
RewriteRule /forum/topic_(.+)\.html$ /forum/viewtopic.php?t=$1 [L]
RewriteRule /forum/forum_(.+)\.html$ /forum/viewforum.php?f=$1 [L]
RewriteRule /forum/user_(.+)\.html$ /forum/profile.php?mode=viewprofile&u=$1 [L]
這樣設置後就可以通過topic_1234.html forum_2.html user_34.html這樣的鏈接訪問原來的動態頁面了。
通過URL REWRITE還有一些好處:
mod_rewrite和isapirewrite基本兼容,但是還是有些不同,比如:isapirewrite中"?"需要轉義成"\?",mod_rewrite不用,isapirewrite支持 "\d+" (全部數字),mod_rewrite不支持
- 隱藏後臺實現:這在後臺應用平臺的遷移時非常有用:當從asp遷移到java平臺時,對於前臺用戶來說,根本感受不到後臺應用的變化;
- 簡化數據校驗:因爲像(\d+)這樣的參數,可以有效的控制數字的格式甚至位數;
比如我們需要將應用從news.asp?id=234遷移成news.php?query=234時,前臺的表現可以一直保持爲 news/234.html。從實現應用和前臺表現的分離:保持了URL的穩定性,而使用mod_rewrite甚至可以把請求轉發到其他後臺服務器上。
基於PATH_INFO的URL美化
Url美化的另外一個方式就是基於PATH_INFO:
PATH_INFO是一個CGI 1.1的標準,經常發現很多跟在CGI後面的"/value_1/value_2"就是PATH_INFO參數:
比如:http://phpunixman.sourceforge.net/index.php/man/ls 中:$PATH_INFO
= "/man/ls"
PATH_INFO是CGI標準,因此PHP Servlet等都有的支持。比如Servlet中就有request.getPathInfo()方法。
注 意:/myapp/servlet/Hello/foo的 getPathInfo()返回的是/foo,而/myapp/dir/hello.jsp/foo的getPathInfo()將返回的 /hello.jsp,從這裏你也可以知道jsp其實就是一個Servlet的PATH_INFO參數。ASP不支持PATH_INFO
PHP中基於PATH_INFO的參數解析的例子如下:
//注意:參數按"/"分割,第一個參數是空的:從/param1/param2中解析出$param1 $param2這2個參數
if ( isset($_SERVER["PATH_INFO"]) ) {
list($nothing, $param1, $param2) = explode('/', $_SERVER["PATH_INFO"]);
}
如何隱蔽應用:例如 .php,的擴展名:
在APACHE中這樣配置:
<FilesMatch "^app_name$">
ForceType application/x-httpd-php
</FilesMatch>
如何更像靜態頁面:app_name/my/app.html
解析的PATH_INFO參數的時候,把最後一個參數的最後5個字符“.html”截斷即可。
注意:APACHE2中缺省是不允許PATH_INFO的,需要設置 AcceptPathInfo on
特別是針對使用虛擬主機用戶,無權安裝和配置mod_rewrite的時候,PATH_INFO往往就成了唯一的選擇。
OK, 這樣以後看見類似於http://www.example.com/article/234這樣的網頁你就知道可能是 article/show.php?id=234這個php程序生成的動態網頁,很多站點表面看上去可能有很多靜態目錄,其實很有可能都是使用1,2個程 序實現的內容發佈。比如很多WIKIWIKI系統都使用了這個機制:整個系統就一個簡單的wiki程序,而看上去的目錄其實都是這個應用拿後面的地址作爲 參數的查詢結果。
利用基於MOD_REWRITE/PATH_INFO + CACHE服務器的解決方案對原有的動態發佈系統進行改造,也可以大大降低舊有系統升級到新的內容管理系統的成本。並且方便了搜索引擎收錄入索引。
本文轉載自:http://blog.chinaunix.net/uid-20639775-id-154471.html