Apache rewrite配置注意事項

mod_rewrite的坑太多。php

1、沒法取得$_SERVER[‘SCRIPT_NAME’]html

當添加rewrite後,寫下如此的規則web

RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule ^(.*)$ /index.php/$1 [QSA,L]正則表達式

打開phpinfo,發現$_SERVER[‘SCRIPT_NAME’]爲」no value」,這在須要判斷script_name的單入口mvc中多是致命的,由於它可能須要用來取得rewrite過的路徑。解決方法是在RewriteRule規則修飾添加PT標記。apache

RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule ^(.*)$ /index.php/$1 [QSA,PT,L]安全

根據rewrite手冊的描述,passthrough|PT標記爲:服務器

Forces the resulting URI to be passed back to the URL mapping engine for processing of other URI-to-filename translators, such as Alias or Redirect.mvc

強制rewrite的URI結果傳遞給映射引擎(mapping engine)處理其它URI與filename的解析,好比別名Alias或轉向Redirect。app

那麼passthroungh究竟是如何工做的呢?webapp

The target (or substitution string) in a RewriteRule is assumed to be a file path, by default. The use of the [PT] flag causes it to be treated as a URI instead. That is to say, the use of the [PT] flag causes the result of the RewriteRule to be passed back through URL mapping, so that location-based mappings, such as Alias, Redirect, or ScriptAlias, for example, might have a chance to take effect.

rewrite後的結果默認會被假定爲一個文件路徑,而[PT]標記的使用則使字串被看成一個URI(url資源)來對待,也就是說,[PT]標記的使用致使RewriteRule處理的結果又被傳回到了URL mapping,這樣方便基於文件路徑的映射計算。舉例:

Alias "/icons" "/usr/local/apache/icons"
RewriteRule "/pics/(.+)\.jpg$" "/icons/$1.gif" [PT]

此例中,省略[PT]標記的結果就是上面的Alias(別名)替換規則被忽略,形成返回「File not found」。由於在路徑/icons中沒法找到*.gif,它實際指向了/user/local/apache/icons/*.gif。

實際,RewriteRull加[PT]標記的流程就是:

uri –> filepath –> [pt] –>uri(replace)->filepath

原本咱們將用戶請求的uri地址映射到服務器系統中實際的文件路徑,找到腳原本處理,但由於pt標記,它還須要將rewrite的結果再轉回一串uri資源,查找替換回真正的路徑地址。

實際最後返回的仍是一個路徑,只不過多了一層映射關係。

PT 標記隱含帶有 L 標記的做用: 將中止rewrite,以便傳遞到下一階段的處理請求。

值得一提的是PT在每一個目錄環境是暗中發揮做用的,例如 <Directory> 塊中或 .htaccess 文件中。避免這一做用的惟一辦法就是將匹配rewrite爲  -。所以,在.htaccess中的RewriteRule的修飾,在有PT的狀況下,沒必要再加L標記。

說了這麼多,尚未交待PT標記與SCRIPT_NAME的關係。實際上這裏也沒交待,惟一能猜想的就是,SCRIPT_NAME值就是在這裏被加上去的。

2、RewriteCond在conf與.htaccess中的不一樣。

具體的錯誤參考這篇博客

在httpd.conf中,若是RewriteConf不添加%{DOCUMENT_ROOT}的地址,input出現的將是相對地址"/a./b"映射後的rewrite,將是'/a/b' -> 'index.php/a/b'。

[rid#9e8030/initial] (4) RewriteCond: input='/a/b' pattern='!-s' => matched

加上後纔會出現絕對地址:

RewriteCond: input='D:/Tomcat/webapps/ROOT/a/b' pattern='!-s' => not-matched

這是由於在文件系統(.htaccess)中,默認就是:

<IfModule rewrite_module>
    RewriteBase /
</IfModule>

所以, .htaccess中的rewrite是相對於.htaceess所在路徑的。而在conf中是不能使用RewriteBase標記當前根目錄的。

因此,在conf中的rewrite的正確寫法應該是:

RewriteCond  %{DOCUMENT_ROOT}%{REQUEST_FILENAME}   !-s
RewriteRule  ^/(.*)$  /index.php/$1   [QAS,L]

注意,index.php前面須要加前導/,表明的是DOCUEMENT_ROOT目錄下的index.php文件,不加會丟失DOCUMENT_ROOT(在.htaccess沒必要)。

三、.htaccess的配置事項

1)、重寫規則的說明。

RewriteRule指令是真正重寫的工做區間。此指令能夠屢次使用,每條指令定義一個單一的重寫規則。其中定義這些規則的順序很是重要 — — 這是將在運行時應用的順序。

Pattern 是 perl 兼容的正則表達式。第一次運用rewrite規則,它對照 (已解碼%) 請求的URL-path,或在per-directory (見下文),URL 路徑相對於當前目錄環境 。隨後的模式對照上次匹配重寫規則的輸出。

2)、如何匹配

在VirtualHost(虛擬主機)方面,Pattern,將是匹配 完主機名和端口剩下的URL部份,在查詢字符串(query string)以前匹配 (例如"/ app1/index.html")。
在Directory和 htaccess 環境,在刪除可以引導服務器至當前的RewriteRule的前綴後,Pattern將優先匹配爲filesystem路徑 (例如"app1/index.html"或"index.html"根據指令在哪裏定義) 。
若是你想匹配的機名、 端口或查詢字符串,分別 使用%{HTTP_HOST},{SERVER_PORT} %或 %{QUERY_STRING} 等RewriteCond。

3、目錄中的重寫

能夠一些額外的工做在.htaccess 文件中和 <Directory>塊中使用rewrite引擎。
在這樣的環境中使用rewrite引擎,您須要設置"RewriteEngine On",並且必須啓用"Options FollowSymLinks"。若是管理員在用戶目錄中禁用了FollowSymLinks,則不能使用rewrite引擎。這是出於安全的須要。

當在 .htaccess文件使用rewrite引擎時,單目錄前綴(對於指定的目錄都是相同的)會被RewriteRul匹配模式自動移除,而且會被規則集自動地替換爲相對的前綴(不能爲前導斜線/或通道名protocal name,例如http://開頭)。有關相對替換前綴的詳細介紹參見RewriteBase指令。

若是須要在單目錄中(.htaccess)匹配完整的URL路徑,請在RewriteCond使用%{REQUEST_URI}變量。

移除的前綴一般以斜槓/結尾,意爲匹配結果將永遠不會出現前導斜線/開頭,所以,^/的 Pattern(匹配模式)將不會找到匹配。(注:一般在.htaccess中的匹配路徑爲^(.*)$)。舉例,

若是請求url爲http://www.xxx.com/a/b/c,那麼,在a目錄下創建的.htaccess,匹配獲得的uri資源對應的將是:

b/c

而非

/b/c

在RewriteDebug中看到的替換結果將是:

rewrite 'b/c' -> 'index.php/b/c'

雖然重寫規則語法規則容許使用在<Location> and <Files>塊(包括相應的正則表達式),但這是沒必要要,也是永遠不支持的作法,這樣產生的一個可能性就是會破壞上下文已經創建的其它重寫規則。

4、一點不解

在個人Apache/2.2.25 (Win32) mod_fcgid/2.3.6版本中,.htaccess的設置沒問題

AcceptPathInfo On

<IfModule rewrite_module>
    RewriteEngine On
    RewriteBase /
    Options FollowSymlinks ExecCGI -Indexes

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index\.php/$1 [QSA,PT,L,NS]
</IfModule>

但始終不能rewrite成功,相同的配置下Apache/2.2.29 fpm-cig卻能夠。是否是由於VirtualHost的緣故?!

最後只能經過?號參數的形式簡接rewrite:

<IfModule rewrite_module>
    RewriteEngine On
    RewriteBase /
    Options FollowSymlinks ExecCGI -Indexes

    RewriteCond %{REQUEST_FILENAME} !-f     RewriteCond %{REQUEST_FILENAME} !-d     RewriteRule ^(.*)$ index\.php?/$1 [QSA,PT,L,NS] </IfModule>

相關文章
相關標籤/搜索