Apache HTTP 伺服器版本 2.4
可透過一個以上的旗標來修改 RewriteRule
的行為。旗標包含在規則結尾的方括號中,而多個旗標則以逗號分隔。
RewriteRule pattern target [Flag1,Flag2,Flag3]
每個標記 (除少數例外) 都有一個簡短的型式,例如 CO
,以及一個較長的型式,例如 cookie
。雖然最常見的是使用簡短的型式,但建議您熟悉較長的型式,以便記住每個標記預期要做什麼。某些標記需要一個或多個參數。標記不區分大小寫。
如果在同一輪重寫處理期間執行取代 (除了「-」之外),在改變與要求有關的資訊 (T =、H =、E =) 的標記在目錄及 htaccess 環境中不會生效。
以下是可用的每個標記,以及如何使用它們的範例。
[B] 標示指示 RewriteRule
在套用轉換之前跳脫非字母數字的字元。
mod_rewrite
在對應之前必須取消 URL 的跳脫,因此反向參照會在套用時被取消跳脫。使用 [B] 標記,反向參照中的非字母數字字元將被跳脫。例如,考慮這條規則
有關伺服器變數類似的跳脫功能,請參閱「跳脫」對應函式
RewriteRule "^search/(.*)$" "/search.php?term=$1"
給定的搜尋項目為「x & y/z」,瀏覽器會將其編碼為「x%20%26%20y%2Fz」,讓要求為「search/x%20%26%20y%2Fz」。如果沒有 [B] 標記,這條重寫規則會對應成「search.php?term=x & y/z」,這並非有效的 URL,因此會被編碼成 search.php?term=x%20&y%2Fz=,這並非預期。
在這條相同的規則中設定 [B] 標記,參數會在傳遞到輸出的 URL 之前重新編碼,進而正確對應到 /search.php?term=x%20%26%20y%2Fz
。
RewriteRule "^search/(.*)$" "/search.php?term=$1" [B,PT]
請注意,您可能也需要將 AllowEncodedSlashes
設定為 開啟
才能讓這個範例運作,因為 httpd 不允許 URL 中有已編碼的斜線,而且如果看到的話會傳回 404。
在代理情況中特別需要這項跳脫,因為後端可能會在傳遞未跳脫的 URL 時中斷。
這個標記的替代方案是使用 RewriteCond
捕捉 %{THE_REQUEST} 中編碼後的字串。
在 2.4.26 和更新版本中,您可以將跳脫限制在反向參照的特定字元上,方法是列出這些字元:[B=#?;]
。注意:空白字元可以用在跳脫字元的清單中,但您必須將 RewriteRule
的第三個參數全部加上引號,而且空白字元不能是清單中的最後一個字元。
# Escape spaces and question marks. The quotes around the final argument # are required when a space is included. RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B= ?]"
針對以這種方式限制跳脫字元,請參閱 #flag_bne 和 #flag_bctls
[BNP] 標記指示 RewriteRule
將反向參照中的空白字元跳脫成 %20,而不是「+」。在將反向參照用於路徑組件 (而非查詢字串) 的時候非常有用。
# Escape spaces to %20 in the path instead of + as used in form submission via # the query string RewriteRule "^search/(.*)$" "/search.php/$1" "[B,BNP]"
這個標記可在 2.4.26 和更新版本使用。
[BCTLS] 標記與 [B] 標記相似,但只會轉義控制字元和空白字元。這些字元與未編碼拷貝至查詢字串時的字元相同。
# Escape control characters and spaces RewriteRule "^search/(.*)$" "/search.php/$1" "[BCTLS]"
此標記於版本 2.4.57 及更新版本中提供。
[BNE=...] 中的字元清單視為對 [B] 或 [BCTLS] 標記的字元例外。所列的字元不會轉義。
# Escape the default characters, but leave / RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B,BNE=/]"
此標記於版本 2.4.57 及更新版本中提供。
[C] 或 [chain] 標記表示將 RewriteRule
連鎖到下一個規則。即,如果此規則相符,則會照常處理,並將控制權轉移到下一個規則。但如果規則不相符,則會略過下一個規則,以及連鎖在一起的其他所有規則。
[CO] 或 [cookie] 標記可在特定的 RewriteRule
相符時設定 cookie。引數包括三個必填欄位和五個選填欄位。
包括所有屬性的標記完整語法如下:
[CO=NAME:VALUE:DOMAIN:lifetime:path:secure:httponly:samesite]
如果任一 cookie 欄位需要分號 (:) 字元,另有替代語法可用。若要使用替代語法,cookie「名稱」之前應加上分號 (;) 字元,欄位分隔符號則應指定為分號 (;)。
[CO=;NAME;VALUE:MOREVALUE;DOMAIN;lifetime;path;secure;httponly;samesite]
您必須宣告名稱、值和網域才能設定 cookie。
www.example.com
,或可能是網域,例如 .example.com
。它必須至少由兩個部分組成,並以句點分隔。亦即它不能只是 .com
或 .net
。依據 cookie 安全性模式,此類型的 cookie 遭到禁止。您也可選擇設定以下值:
/customers/
或 /files/download/
。/
- 亦即整個網站。secure
、true
或 1
,則只允許透過安全 (https) 連線傳輸 cookie。HttpOnly
、true
或 1
,則會為 cookie 設定 HttpOnly
標記,表示無法透過支援此功能的瀏覽器存取此 cookie。false
或 0
,將 SameSite
屬性設為指定的值。常見的值為 None
、Lax
和 Strict
。適用於 2.4.47 及更新版本。考量以下範例
RewriteEngine On RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.com:1440:/]
在提供的範例中,此規則並不會重寫要求。將「-」改寫目標告知 mod_rewrite 以不改變地傳遞要求。相反地,它將一個稱為「frontdoor」的 cookie 設為「yes」。此 cookie 對 .example.com
網域中的任何主機都有效。它被設為在 1440 分鐘(24 小時)後過期,並針對所有 URI 返回。
DPI 標記會讓 PATH_INFO的部分被改寫為 URI 被捨棄。
此標記適用於版本 2.2.12 及更新版本。
在每個目錄的內容中,每個 RewriteRule
做比較時提供的 URI 是從 URI 的目前值和 PATH_INFO 連接而成的。
目前的 URI 可以為用戶端所要求的初始 URI,mod_rewrite 處理的最後一個回合的結果,或 mod_rewrite 處理的目前回合中某個規則的結果。
相對而言,在每個規則前加到 URI 中的 PATH_INFO 僅反映此回合 mod_rewrite 處理之前 PATH_INFO 的值。因此,如果 URI 的大部份都配合並複製到多個 RewriteRule
指令的替代品中,而不管 URI 的哪個部份來自目前的 PATH_INFO,最終 URI 會有多個 PATH_INFO 複本加在上面。
在這個要求對檔案系統的先前對應中所產生的 PATH_INFO 不重要的任何替代品中,請使用此標記。此標記會永久忘記在這個回合的 mod_rewrite 處理開始前建立的 PATH_INFO。在目前的 mod_rewrite 處理回合完成之前 PATH_INFO 都不會重新計算。此處理回合的後續規則只會看到替代品的直接結果,而不會加上任何 PATH_INFO。
使用 [E] 或 [env] 標記,你可以設定環境變數的值。請注意,一些環境變數會在你執行規則後設定,因此會解除你所設定的內容。請參閱 環境變數文件,取得有關環境變數運作的更多詳細資訊。
此標記的完整語法為:
[E=VAR:VAL] [E=!VAR]
VAL
中可能包含反向參照 ($N
或 %N
),而這些會被展開。
使用簡短格式
[E=VAR]
你可以將名為 VAR
的環境變數設定為空值。
格式
[E=!VAR]
允許取消設定先前設定名為 VAR
的環境變數。
環境變數可以在許多不同的脈絡中使用,包含 CGI 程式、其他 RewriteRule 指令或 CustomLog 指令。
以下範例會設定一個環境變數稱為「image」,如果請求的 URI 是圖檔,其值為「1」。接著,會使用該環境變數從存取日誌中將那些請求排除。
RewriteRule "\.(png|gif|jpg)$" "-" [E=image:1] CustomLog "logs/access_log" combined env=!image
請注意,也可以使用 SetEnvIf
產生相同的結果。這個技巧提供的是範例,並非建議。
使用 [F] 旗標會讓伺服器傳回 403 禁止狀態碼給用戶端。雖然可以使用 Deny
指令來產生相同的行為,但這能提供更具彈性的方式來指定禁止狀態。
以下規則會禁止從您的伺服器下載 .exe
檔案。
RewriteRule "\.exe" "-" [F]
這個範例使用改寫目標的「-」語法,這表示不會修改請求的 URI。如果您要禁止請求,就沒有理由改寫成另外一個 URI。
使用 [F] 時,會隱含 [L] - 也就是,立即傳回回應,並且不會評估進一步的規則。
〔G〕旗標會強制伺服器在回應中傳回 410 已消失狀態。這表示資源曾經可用,但現在已不再可用。
與〔F〕旗標相同,通常會在使用〔G〕旗標時為改寫目標使用「-」語法
RewriteRule "oldproduct" "-" [G,NC]
使用 [G] 時,會隱含 [L] - 也就是,立即傳回回應,並且不會評估進一步的規則。
強制將結果要求處理使用指定處理常式。例如,有人可能會使用這個方法強制所有沒有檔案副檔名的檔案由 PHP 處理常式來剖析
RewriteRule "!\." "-" [H=application/x-httpd-php]
上述正規表示式 - !\.
- 會比對所有不包含字元 .
的請求。
這也可以用於根據某些條件強制處理常式。例如,以下片段用於每個伺服器的脈絡中允許 .php
檔案由 mod_php
顯示,如果這些檔案是用 .phps
副檔名所請求的。
RewriteRule "^(/source/.+\.php)s$" "$1" [H=application/x-httpd-php-source]
上述正規表示式 - ^(/source/.+\.php)s$
- 會比對任何從 /source/
開始的請求,其後是 1 或 n 個字元,最後是 .phps
。反向參照 $1 指向正規表示式括號內所擷取的比對結果。
〔L〕旗標會讓 mod_rewrite
停止處理規則組。在大部分脈絡中,這表示如果規則比對相符,就不會處理進一步的規則。這會對應於 Perl 中的 last
指令和 C 中的 break
指令。使用這個旗標表示目前的規則應該立即套用,而不考慮進一步的規則。
如果您在 .htaccess
檔案或
區段中使用 RewriteRule
指令,了解如何處理這些規則非常重要。其簡化的形式在於,規則經過處理後,已重寫的請求會交還給 URL 解析引擎,由引擎決定如何處理。在處理已重寫請求時有可能會再次遇到 .htaccess
檔案或
區段,因而規則集可能從頭執行一次。最常見的情況是其中一個規則導致重新導向 (內部或外部),導致請求程序重新啟動。
因此,如果您在這些情境之一中使用 RewriteRule
指令,很重要的一點是您必須採取明確的步驟來避免規則循環,並不能僅依賴於 [L] 標記來終止執行一系列的規則,如下所示。
可以使用替代標記 [END],不僅終止當前這輪的重寫處理程序,還可避免在每個目錄 (htaccess) 情境中發生任何後續的重寫處理程序。這不適用於外部重新導向所產生的新請求。
這裡給的範例會將任何請求重寫為 index.php
,將原始請求作為查詢字串參數提供給 index.php
,然而,RewriteCond
確保如果請求已經是 index.php
,則會略過 RewriteRule
。
RewriteBase "/" RewriteCond "%{REQUEST_URI}" !=/index.php RewriteRule "^(.*)" "/index.php?req=$1" [L,PT]
[N] 標記會導致規則集從頭開始再次執行,使用到目前為止的規則集結果作為起點。極為不建議使用,因為這樣可能會產生循環。
例如,如果您希望在請求中重複取代某個字串或字母,可以使用 [Next] 標記。這裡所示的範例會在請求中將 A 取代為 B,而且會持續這樣做,直到沒有更多的 A 可以取代為止。
RewriteRule "(.*)A(.*)" "$1B$2" [N]
您可以將其想成一個 while
循環:當這個樣式仍符合時 (亦即,當 URI 中仍包含 A
時),執行這個置換 (亦即,將 A
取代為 B
)。
在 2.4.8 及更新版本中,此模組會在 10,000 次疊代後傳回錯誤,以防範意外循環。可以透過新增 N 標記,指定疊代的備用最大次數。
# Be willing to replace 1 character in each pass of the loop RewriteRule "(.+)[><;]$" "$1" [N=32000] # ... or, give up if after 10 loops RewriteRule "(.+)[><;]$" "$1" [N=10]
使用 [NC] 標記會導致 RewriteRule
以不區分大小寫的方式進行比對。換句話說,它不在意所比對的 URI 中的字母是大寫還是小寫。
在以下範例中,對於影像檔的任何請求都將透過代理傳遞至您專用的影像伺服器。這個比對不區分大小寫,因此例如 .jpg
和 .JPG
檔都是可以接受的。
RewriteRule "(.*\.(jpg|gif|png))$" "http://images.example.com$1" [P,NC]
預設情況下,特殊字元,例如 &
和 ?
,在會產生外部重新導向的規則中,會轉換成它們相對應的十六進位碼。使用 [NE] 旗標可以避免轉換。
RewriteRule "^/anchor/(.+)" "/bigpage.html#$1" [NE,R]
上面的範例會將 /anchor/xyz
重新導向至 /bigpage.html#xyz
。不使用 [NE] 會導致將 # 轉換成相對應的十六進位碼 %23
,進而產生 404 找不到錯誤狀況。
使用 [NS] 旗標可以禁止在子請求中使用這項規則。例如,使用 SSI(伺服器端包含)包含的網頁即為一項子請求,您可能需要避免對這些子請求進行重寫。另外,當 mod_dir
嘗試尋找關於可能目錄預設檔(例如 index.html
檔)的資訊時,這項子請求是內部子請求,您通常想要避免重寫此類子請求。在子請求中,應用完整規則集並不總是實用的,甚至會導致錯誤。使用這項旗標來排除有問題的規則。
決定是否使用此規則的方法:如果您在 CGI 程式碼中加上一組 URL 前置字元,以強制要求由 CGI 程式碼處理這些 URL,您很可能會在子請求中遭遇問題(或明顯的負擔)。在這些情況下,請使用此旗標。
作為 HTML 頁面一部分載入的圖片、javascript 檔案,或 css 檔案並非子請求,瀏覽器會要求將他們視為個別的 HTTP 請求來處理。
使用 [P] 旗標會讓請求交由 mod_proxy
處理,並透過代理請求處理。例如,如果您希望全部的圖片請求都交由後端圖片伺服器處理,您可以執行類似下列的動作
RewriteRule "/(.*)\.(jpg|gif|png)$" "http://images.example.com/$1.$2" [P]
使用 [P] 旗標表示 [L],換句話說,請求會直接透過代理伺服器處理,後面任何的規則都不會被考慮。
您必須確保替換字串為 mod_proxy
可以處理的有效 URI(通常以 http://
主機名稱 開頭)。如果沒有,您會收到來自代理模組的錯誤訊息。使用這個旗標實現 ProxyPass
指令更強大的功能,將遠端內容對應到本地端伺服器的命名空間。
在建構規則的目標 URL 時,務必考慮允許用戶影響伺服器作為代理伺服器所處理的 URL 集所造成的安全性影響。確保 URL 的目的和主機部分為固定值,或不會允許用戶過度影響。
使用此旗標會觸發 mod_proxy
的使用,在這個案例中不處理持續性連線,因為預設工作執行緒不處理連線串集/重新使用。
要使用持續連線,您至少需要針對含有一個 ProxySet
指令的目標 URL 的架構和主機部分,設定一個 Proxy
區塊,例如在此設定逾時時間。
如果你使用 ProxyPass
或 ProxyPassMatch
設定它,它會自動使用持續連線。
注意:mod_proxy
必須啟用才能使用此標記。
預設情況下,RewriteRule 中的目標(或取代字串)假設為檔案路徑。使用 [PT] 標記會將它當作 URI 處理。亦即,使用 [PT] 標記會導致 RewriteRule
的結果透過 URL 對應傳遞回去,這代表基於位置的對應,例如 Alias
、Redirect
或 ScriptAlias
,將有機會發生效用。
舉例來說,如果你有一個指向 /icons 的 Alias
,並有一個指向那裡的 RewriteRule
,你應該使用 [PT] 標記來確保 Alias
已評估。
Alias "/icons" "/usr/local/apache/icons" RewriteRule "/pics/(.+)\.jpg$" "/icons/$1.gif" [PT]
這種情況下省略 [PT] 標記將導致 Alias 被忽略,進而產生「檔案未找到」的錯誤。
PT
標記會暗示使用 L
標記:編寫會停止,以傳遞要求給下一個處理階段。
請注意,在每個目錄的內容中暗示使用 PT
標記,例如 <Directory>
部分或在 .htaccess
檔案中。避免此情況的唯一方法是改寫為 -
。
當取代的 URI 包含查詢字串時,RewriteRule
的預設行為會丟棄現有的查詢字串,並將它取代為新產生的字串。使用 [QSA] 標記會導致查詢字串被組合起來。
考慮以下規則
RewriteRule "/pages/(.+)" "/page.php?page=$1" [QSA]
使用 [QSA] 標記,要求為 /pages/123?one=two
會對應到 /page.php?page=123&one=two
。不使用 [QSA] 標記,同一個要求會對應到 /page.php?page=123
,亦即現有的查詢字串會被丟棄。
當要求的 URI 包含查詢字串,而目標 URI 沒有,RewriteRule
的預設行為會將該查詢字串複製到目標 URI。使用 [QSD] 標記會導致查詢字串被丟棄。
此標誌可用於 2.4.0 及更新版本。
如果同時使用 [QSD] 和 [QSA],[QSD] 會優先處理。
如果目標 URI 具有查詢字串,則會觀察到預設行為,即捨棄原始查詢字串,並用 RewriteRule
目標 URI 中的查詢字串替換它。
在替代中,預設情況下,第一個 (最左邊的) 問號會將路徑與查詢字串分隔。使用 [QSL] 標誌會指示 RewriteRule
改用最後一個 (最右邊的) 問號來拆分兩個元件。
在對應到檔案名稱中有實際問號的檔案時,這很有用。如果在替代中未使用的查詢字串,可以使用此標誌在後方加上問號。
此標誌可用於 2.4.19 及更新版本。
使用 [R] 標誌會導致發出 HTTP 重新導向到瀏覽器。如果指定完全限定的 URL (即包含 http://servername/
),則會發出重新導向到該位置。否則,將使用目前的通訊協定、伺服器名稱和埠號來產生重新導向時附送的 URL。
任何 有效的 HTTP 回應狀態代碼都能用 [R=305] 語法指定,如果未指定任何,則預設會使用 302 狀態代碼。指定的狀態代碼不必是重新導向 (3xx) 狀態代碼。不過,如果狀態代碼不在重新導向範圍 (300-399) 中,則替代字串會完全捨棄,並停止改寫,就好像使用 L
一樣。
除了回應狀態代碼之外,也可以使用它們的符號名稱指定重新導向狀態:temp
(預設)、permanent
或 seeother
。
在與 [L] 結合使用 [R] 時,你幾乎總是想使用 [R] (也就是使用 [R,L]),因為 [R] 標誌本身會在 URI 前加上 http://thishost[:thisport]
,但之後會傳遞到規則集中下一條規則,這可能經常導致「要求中有無效 URI」警告。
要跳過不想執行的規則時,可以使用 [S] 標誌。跳過標誌的語法為 [S=N],其中 N 表示要跳過的規則數目 (假設 RewriteRule
和任何之前的 RewriteCond
指令相符)。這可以視為改寫規則集中的 goto
語句,在以下範例中,我們只想要在要求的 URI 不對應到實際檔案時,才會執行 RewriteRule
。
# Is the request for a non-existent file? RewriteCond "%{REQUEST_FILENAME}" !-f RewriteCond "%{REQUEST_FILENAME}" !-d # If so, skip these two RewriteRules RewriteRule ".?" "-" [S=2] RewriteRule "(.*\.gif)" "images.php?$1" RewriteRule "(.*\.html)" "docs.php?$1"
這項技術非常實用,因為RewriteCond
僅適用於緊接在後面的RewriteRule
。因此,如果您想要讓RewriteCond
適用於多個RewriteRule
,其中一種類似技術是讓這些條件變為否定式,然後加一個[Skip]標記的RewriteRule
。您可以使用它建立類似的if-then-else架構:then子句的最後一個規則會變成skip=N
,其中N是else子句中規則的數目
# Does the file exist? RewriteCond "%{REQUEST_FILENAME}" !-f RewriteCond "%{REQUEST_FILENAME}" !-d # Create an if-then-else construct by skipping 3 lines if we meant to go to the "else" stanza. RewriteRule ".?" "-" [S=3] # IF the file exists, then: RewriteRule "(.*\.gif)" "images.php?$1" RewriteRule "(.*\.html)" "docs.php?$1" # Skip past the "else" stanza. RewriteRule ".?" "-" [S=1] # ELSE... RewriteRule "(.*)" "404.php?file=$1" # END
使用<If>
、<ElseIf>
和<Else>
指令來完成這類設定可能會比較容易。
設定結果回應發送時所使用的MIME類型。這與AddType
指令的效果相同。
舉例來說,如果您有特別要求,您可以使用以下技術將Perl原始程式碼提供為純文字
# Serve .pl files as plain text RewriteRule "\.pl$" "-" [T=text/plain]
或者,如果您有一個照相手機產生的jpeg影像沒有檔案副檔名,您可以強制套用正確的MIME類型在這些影像的檔案名稱中
# Files with 'IMG' in the name are jpg images. RewriteRule "IMG" "-" [T=image/jpg]
請注意,這是個微不足道的範例,可以使用<FilesMatch>
取得更好的成果。在求助改寫之前,請務必考慮問題的其他解決方案,因為與其他替代方案相比,改寫會是一個效率較差的解決方案。
如果在目錄範圍的環境中使用,請僅將連字符(-)做為代換(全面處理mod_rewrite時),否則由於內部重新處理(包括後續處理mod_rewrite的步驟),將會遺失以此標記設定的MIME類型。在此情況下,L
標記可在結束目前處理mod_rewrite的步驟時派上用場。
若要允許重寫繼續進行,請務必設定此標記,如果正在編寫的HTTP請求有編碼問號「%3f」,而且重新編寫的結果在代換中有一個「?」。這可避免惡意的URL利用編碼問號的擷取和重新代換。
如果伺服器範圍內的代換從一個變數或反向參考開始,而且解析到檔案系統的路徑,則必須設定此標記。這些代換不會加上文件根目錄。這可避免惡意的URL導致展開代換會對應到預期之外的檔案系統位置。