<-
Apache > HTTP Server > 文件 > 版本 2.4 > 重寫

重寫規則旗標

可用語言:  英文  |  法文 

本文件探討可供 RewriteRule 指令使用的旗標,並提供詳細的說明和範例。

Support Apache!

另請參閱

top

簡介

可透過一個以上的旗標來修改 RewriteRule 的行為。旗標包含在規則結尾的方括號中,而多個旗標則以逗號分隔。

RewriteRule pattern target [Flag1,Flag2,Flag3]

每個標記 (除少數例外) 都有一個簡短的型式,例如 CO,以及一個較長的型式,例如 cookie。雖然最常見的是使用簡短的型式,但建議您熟悉較長的型式,以便記住每個標記預期要做什麼。某些標記需要一個或多個參數。標記不區分大小寫。

如果在同一輪重寫處理期間執行取代 (除了「-」之外),在改變與要求有關的資訊 (T =、H =、E =) 的標記在目錄及 htaccess 環境中不會生效。

以下是可用的每個標記,以及如何使用它們的範例。

top

B (跳脫反向參照)

[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

top

BNP|backrefnoplus (不將空白跳脫成 +)

[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 和更新版本使用。

top

BCTLS

[BCTLS] 標記與 [B] 標記相似,但只會轉義控制字元和空白字元。這些字元與未編碼拷貝至查詢字串時的字元相同。

# Escape control characters and spaces
RewriteRule "^search/(.*)$" "/search.php/$1" "[BCTLS]"

此標記於版本 2.4.57 及更新版本中提供。

top

BNE

[BNE=...] 中的字元清單視為對 [B] 或 [BCTLS] 標記的字元例外。所列的字元不會轉義。

# Escape the default characters, but leave /
RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B,BNE=/]"

此標記於版本 2.4.57 及更新版本中提供。

top

C|chain

[C] 或 [chain] 標記表示將 RewriteRule 連鎖到下一個規則。即,如果此規則相符,則會照常處理,並將控制權轉移到下一個規則。但如果規則不相符,則會略過下一個規則,以及連鎖在一起的其他所有規則。

top

CO|cookie

[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。

網域
您要讓 cookie 生效的網域。這可能是網域名稱,例如 www.example.com,或可能是網域,例如 .example.com。它必須至少由兩個部分組成,並以句點分隔。亦即它不能只是 .com.net。依據 cookie 安全性模式,此類型的 cookie 遭到禁止。

您也可選擇設定以下值:

Cookie 生存期
cookie 持續存在的時間(以分鐘為單位)。
值 0 表示 cookie 僅持續目前瀏覽器工作階段。如果未指定值,則此為預設值。
路徑
cookie 在目前網站上生效的路徑,例如 /customers//files/download/
預設值為 / - 亦即整個網站。
安全
如果設為 securetrue1,則只允許透過安全 (https) 連線傳輸 cookie。
僅限 http
如果設為 HttpOnlytrue1,則會為 cookie 設定 HttpOnly 標記,表示無法透過支援此功能的瀏覽器存取此 cookie。
同網站
若設定為非 false0,將 SameSite 屬性設為指定的值。常見的值為 NoneLaxStrict。適用於 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 返回。

top

DPI|discardpath

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。

top

E|env

使用 [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 產生相同的結果。這個技巧提供的是範例,並非建議。

top

END

[END] 旗標的使用不僅會終止目前的改寫處理巡迴 (與 [L] 相似),還能防止任何後續的改寫處理在每個目錄 (htaccess) 脈絡中發生。

這不適用於來自外部重新導向所導致的新請求。

top

F|禁止

使用 [F] 旗標會讓伺服器傳回 403 禁止狀態碼給用戶端。雖然可以使用 Deny 指令來產生相同的行為,但這能提供更具彈性的方式來指定禁止狀態。

以下規則會禁止從您的伺服器下載 .exe 檔案。

RewriteRule "\.exe"   "-" [F]

這個範例使用改寫目標的「-」語法,這表示不會修改請求的 URI。如果您要禁止請求,就沒有理由改寫成另外一個 URI。

使用 [F] 時,會隱含 [L] - 也就是,立即傳回回應,並且不會評估進一步的規則。

top

G|已消失

〔G〕旗標會強制伺服器在回應中傳回 410 已消失狀態。這表示資源曾經可用,但現在已不再可用。

與〔F〕旗標相同,通常會在使用〔G〕旗標時為改寫目標使用「-」語法

RewriteRule "oldproduct"   "-" [G,NC]

使用 [G] 時,會隱含 [L] - 也就是,立即傳回回應,並且不會評估進一步的規則。

top

H|處理常式

強制將結果要求處理使用指定處理常式。例如,有人可能會使用這個方法強制所有沒有檔案副檔名的檔案由 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 指向正規表示式括號內所擷取的比對結果。

top

L|最後

〔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]
top

N|next

[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]
top

NC|nocase

使用 [NC] 標記會導致 RewriteRule 以不區分大小寫的方式進行比對。換句話說,它不在意所比對的 URI 中的字母是大寫還是小寫。

在以下範例中,對於影像檔的任何請求都將透過代理傳遞至您專用的影像伺服器。這個比對不區分大小寫,因此例如 .jpg.JPG 檔都是可以接受的。

RewriteRule "(.*\.(jpg|gif|png))$" "http://images.example.com$1" [P,NC]
top

NE|noescape

預設情況下,特殊字元,例如 &?,在會產生外部重新導向的規則中,會轉換成它們相對應的十六進位碼。使用 [NE] 旗標可以避免轉換。

RewriteRule "^/anchor/(.+)" "/bigpage.html#$1" [NE,R]

上面的範例會將 /anchor/xyz 重新導向至 /bigpage.html#xyz。不使用 [NE] 會導致將 # 轉換成相對應的十六進位碼 %23,進而產生 404 找不到錯誤狀況。

top

NS|nosubreq

使用 [NS] 旗標可以禁止在子請求中使用這項規則。例如,使用 SSI(伺服器端包含)包含的網頁即為一項子請求,您可能需要避免對這些子請求進行重寫。另外,當 mod_dir 嘗試尋找關於可能目錄預設檔(例如 index.html 檔)的資訊時,這項子請求是內部子請求,您通常想要避免重寫此類子請求。在子請求中,應用完整規則集並不總是實用的,甚至會導致錯誤。使用這項旗標來排除有問題的規則。

決定是否使用此規則的方法:如果您在 CGI 程式碼中加上一組 URL 前置字元,以強制要求由 CGI 程式碼處理這些 URL,您很可能會在子請求中遭遇問題(或明顯的負擔)。在這些情況下,請使用此旗標。

作為 HTML 頁面一部分載入的圖片、javascript 檔案,或 css 檔案並非子請求,瀏覽器會要求將他們視為個別的 HTTP 請求來處理。

top

P|proxy

使用 [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 區塊,例如在此設定逾時時間。

如果你使用 ProxyPassProxyPassMatch 設定它,它會自動使用持續連線。

注意:mod_proxy 必須啟用才能使用此標記。

top

PT|passthrough

預設情況下,RewriteRule 中的目標(或取代字串)假設為檔案路徑。使用 [PT] 標記會將它當作 URI 處理。亦即,使用 [PT] 標記會導致 RewriteRule 的結果透過 URL 對應傳遞回去,這代表基於位置的對應,例如 AliasRedirectScriptAlias,將有機會發生效用。

舉例來說,如果你有一個指向 /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 檔案中。避免此情況的唯一方法是改寫為 -

top

QSA|qsappend

當取代的 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 ,亦即現有的查詢字串會被丟棄。

top

QSD|qsdiscard

當要求的 URI 包含查詢字串,而目標 URI 沒有,RewriteRule 的預設行為會將該查詢字串複製到目標 URI。使用 [QSD] 標記會導致查詢字串被丟棄。

此標誌可用於 2.4.0 及更新版本。

如果同時使用 [QSD] 和 [QSA],[QSD] 會優先處理。

如果目標 URI 具有查詢字串,則會觀察到預設行為,即捨棄原始查詢字串,並用 RewriteRule 目標 URI 中的查詢字串替換它。

top

QSL|qslast

在替代中,預設情況下,第一個 (最左邊的) 問號會將路徑與查詢字串分隔。使用 [QSL] 標誌會指示 RewriteRule 改用最後一個 (最右邊的) 問號來拆分兩個元件。

在對應到檔案名稱中有實際問號的檔案時,這很有用。如果在替代中未使用的查詢字串,可以使用此標誌在後方加上問號。

此標誌可用於 2.4.19 及更新版本。

top

R|重新導向

使用 [R] 標誌會導致發出 HTTP 重新導向到瀏覽器。如果指定完全限定的 URL (即包含 http://servername/),則會發出重新導向到該位置。否則,將使用目前的通訊協定、伺服器名稱和埠號來產生重新導向時附送的 URL。

任何 有效的 HTTP 回應狀態代碼都能用 [R=305] 語法指定,如果未指定任何,則預設會使用 302 狀態代碼。指定的狀態代碼不必是重新導向 (3xx) 狀態代碼。不過,如果狀態代碼不在重新導向範圍 (300-399) 中,則替代字串會完全捨棄,並停止改寫,就好像使用 L 一樣。

除了回應狀態代碼之外,也可以使用它們的符號名稱指定重新導向狀態:temp (預設)、permanentseeother

在與 [L] 結合使用 [R] 時,你幾乎總是想使用 [R] (也就是使用 [R,L]),因為 [R] 標誌本身會在 URI 前加上 http://thishost[:thisport],但之後會傳遞到規則集中下一條規則,這可能經常導致「要求中有無效 URI」警告。

top

S|跳過

要跳過不想執行的規則時,可以使用 [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>指令來完成這類設定可能會比較容易。

top

T|類型

設定結果回應發送時所使用的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的步驟時派上用場。

top

UnsafeAllow3F

若要允許重寫繼續進行,請務必設定此標記,如果正在編寫的HTTP請求有編碼問號「%3f」,而且重新編寫的結果在代換中有一個「?」。這可避免惡意的URL利用編碼問號的擷取和重新代換。

top

UnsafePrefixStat

如果伺服器範圍內的代換從一個變數或反向參考開始,而且解析到檔案系統的路徑,則必須設定此標記。這些代換不會加上文件根目錄。這可避免惡意的URL導致展開代換會對應到預期之外的檔案系統位置。

可用語言:  英文  |  法文 

top

附註

注意
這裡並不是問答區。置於此處的意見應指向改善文件或伺服器的建議,如果已實作或被視為無效/離題,可能會由我們的管理員移除。關於如何管理 Apache HTTP Server 的問題應導向我們位於 Libera.chat 的 IRC 頻道 #httpd,或寄送至我們的 郵寄清單