RewriteRule Flags

本文档讨论了RewriteRule指令可用的标志,并提供了详细的说明和示例。

Introduction

RewriteRule可以通过一个或多个标志来修改其行为。规则末尾的方括号中包含标志,多个标志之间用逗号分隔。

RewriteRule pattern target [Flag1,Flag2,Flag3]

每个标志(除少数 exception)都有一个简短的形式(例如CO)和一个更长的形式(例如cookie)。虽然最常用的是短格式,但建议您熟悉长格式,以便记住每个标志应该做什么。一些标志带有一个或多个参数。标志不区分大小写。

当在同一轮重写处理期间执行替换(“-”除外)时,更改与请求关联的元数据的标志(T =,H =,E =)在按目录和 htaccess 上下文中不起作用。

这里提供了每个可用标志,以及如何使用它们的示例。

B(转义反向引用)

[B]标志指示RewriteRule在应用转换前转义非字母数字字符。

在 2.4.26 及更高版本中,您可以通过列出反向引用中的特定字符来限制转义:[B=#?;]。注意:可以在字符列表中使用空格字符进行转义,但不能是列表中的最后一个字符。

mod_rewrite必须先对 URL 进行转义,然后再对它们进行 Map,因此在应用反向引用时,将不对它们进行转义。使用 B 标志,反向引用中的非字母数字字符将被转义。例如,考虑以下规则:

RewriteRule "^search/(.*)$" "/search.php?term=$1"

给定搜索词“ x&y/z”,浏览器会将其编码为“ x%20%26%20y%2Fz”,从而发出请求“ search/x%20%26%20y%2Fz”。没有 B 标志,此重写规则将 Map 到'search.php?term = x&y/z',这不是有效的 URL,因此将被编码为search.php?term=x%20&y%2Fz=,这不是预期的。

在此相同规则上设置 B 标志的情况下,参数将在传递到输出 URL 之前重新编码,从而正确 Map 到/search.php?term=x%20%26%20y%2Fz

RewriteRule "^search/(.*)$" "/search.php?term=$1" [B,PT]

请注意,您可能还需要将AllowEncodedSlashes设置为On才能使此特定示例正常工作,因为 httpd 不允许 URL 中使用编码的斜杠,如果看到则返回 404.

在代理情况下,如果后端如果显示有未转义的 URL 可能会损坏,则这种转义尤其必要。

此标志的替代方法是使用RewriteCond捕获%\ {},后者将捕获编码形式的字符串。

BNP | backrefnoplus(请勿向逃脱空间)

[BNP]标志指示RewriteRule以%20 而不是''的后向引用转义空格字符。当在路径组件而不是查询字符串中使用反向引用时很有用。

该标志在 2.4.26 及更高版本中可用。

C|chain

[C]或[chain]标志指示RewriteRule已链接到下一个规则。也就是说,如果规则匹配,则照常进行处理,然后控制移至下一条规则。但是,如果不匹配,则将跳过下一个规则以及链接在一起的任何其他规则。

CO|cookie

[CO]或[cookie]标志允许您在特定的RewriteRule匹配时设置 cookie。该参数包含三个必填字段和四个可选字段。

该标志的完整语法,包括所有属性,如下所示:

[CO=NAME:VALUE:DOMAIN:lifetime:path:secure:httponly]

如果在任何 cookie 字段中需要 Literals':'字符,则可以使用其他语法。要选择使用其他语法,cookie 的“名称”前应带有“;”字符,并且字段分隔符应指定为“;”。

[CO=;NAME;VALUE:MOREVALUE;DOMAIN;lifetime;path;secure;httponly]

您必须声明名称,值和域才能设置 Cookie。

您还可以选择设置以下值:

考虑以下示例:

RewriteEngine On
RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.com:1440:/]

在给出的示例中,规则不重写请求。 “-”重写目标告诉 mod_rewrite 通过不变的方式传递请求。而是将名为“前门”的 cookie 设置为“是”。该 cookie 对.example.com域中的任何主机有效。它设置为在 1440 分钟(24 小时)内到期,并为所有 URI 返回。

DPI|discardpath

DPI 标志导致重写的 URI 的 PATH_INFO 部分被丢弃。

此标志在 2.2.12 版本和更高版本中可用。

在每个目录上下文中,每个RewriteRule所比较的 URI 是 URI 和 PATH_INFO 的当前值的串联。

当前 URI 可以是 Client 端请求的初始 URI,也可以是上一轮 mod_rewrite 处理的结果,也可以是当前一轮 mod_rewrite 处理中的先前规则的结果。

相反,在每个规则之前附加到 URI 的 PATH_INFO 仅反映此轮 mod_rewrite 处理之前的 PATH_INFO 的值。因此,如果 URI 的大部分被匹配并复制到多个RewriteRule指令中以替换,而不考虑 URI 的哪些部分来自当前 PATH_INFO,则最终 URI 可能会附加 PATH_INFO 的多个副本。

在不需要此请求到文件系统的先前 Map 所导致的 PATH_INFO 的任何替换上,请使用此标志。该标志永久忘记在此轮 mod_rewrite 处理开始之前构建的 PATH_INFO。在当前一轮的 mod_rewrite 处理完成之前,不会重新计算 PATH_INFO。在这一轮处理中的后续规则将仅看到替换的直接结果,而未附加任何 PATH_INFO。

E|env

使用[E]或[env]标志,可以设置环境变量的值。请注意,在运行规则后可能会设置一些环境变量,从而取消设置的内容。有关环境变量如何工作的更多详细信息,请参见环境变量文档

此标志的完整语法为:

[E=VAR:VAL]
[E=!VAR]

VAL可以包含扩展的反向引用($N%N)。

使用简写形式

[E=VAR]

您可以将名为VAR的环境变量设置为空值。

The form

[E=!VAR]

允许取消设置先前设置的名为VAR的环境变量。

然后可以在各种上下文中使用环境变量,包括 CGI 程序,其他 RewriteRule 指令或 CustomLog 指令。

如果请求的 URI 是图像文件,则以下示例将名为“ image”的环境变量设置为“ 1”。然后,该环境变量用于从访问日志中排除那些请求。

RewriteRule "\.(png|gif|jpg)$" "-" [E=image:1]
CustomLog "logs/access_log" combined env=!image

请注意,使用SetEnvIf可以获得相同的效果。提供此技术仅作为示例,而不作为推荐。

END

使用[END]标志不仅终止当前的重写处理(如[L]),而且还可以防止在每个目录(htaccess)上下文中发生任何后续的重写处理。

这不适用于外部重定向产生的新请求。

F|forbidden

使用[F]标志会使服务器向 Client 端返回 403 Forbidden 状态代码。尽管可以使用Deny指令实现相同的行为,但这在分配禁止状态方面具有更大的灵 Active。

以下规则将禁止从服务器下载.exe个文件。

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

本示例对重写目标使用“-”语法,这意味着未修改请求的 URI。如果您要禁止该请求,则没有理由重写为另一个 URI。

使用[F]时,隐含一个[L]-即立即返回响应,并且不评估其他规则。

G|gone

[G]标志强制服务器返回 410 Gone 状态和响应。这表明资源曾经可用,但是不再可用。

与[F]标志一样,在使用[G]标志时,通常会将“-”语法用于重写目标:

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

使用[G]时,隐含一个[L]-即立即返回响应,并且不评估其他规则。

H|handler

强制使用指定的处理程序处理结果请求。例如,一个人可能会用它来强制所有没有文件 extensions 的文件被 php 处理程序解析:

RewriteRule "!\." "-" [H=application/x-httpd-php]

上面的正则表达式!\.将匹配任何不包含 Literals.字符的请求。

这也可以用于根据某些条件强制处理程序。例如,在每个服务器上下文中使用的以下代码段允许.php文件通过.phpsextensions 被mod_php 显示

RewriteRule "^(/source/.+\.php)s$" "$1" [H=application/x-httpd-php-source]

上面的正则表达式^(/source/.+\.php)s$将匹配任何以/source/开头,后跟 1 或 n 个字符,再按.phps字面意义的请求。向后引用$ 1 引用正则表达式括号内的已捕获匹配。

L|last

[L]标志使mod_rewrite停止处理规则集。在大多数情况下,这意味着如果规则匹配,将不再处理其他规则。这对应于 Perl 中的last命令或 C 中的break命令。使用此标志指示应立即应用当前规则,而不考虑其他规则。

如果要在.htaccess文件或<Directory>部分中使用RewriteRule,那么一定要了解规则的处理方式,这一点很重要。简化的形式是,一旦处理完规则,重写的请求就会交还给 URL 解析引擎,以对其进行处理。在处理重写的请求时,可能会再次遇到.htaccess文件或<Directory>部分,因此规则集可能从头开始运行。最常见的情况是,如果其中一个规则导致重定向(内部或外部)导致请求过程重新开始,则将发生这种情况。

因此,重要的是,如果您在其中一种上下文中使用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

[N]标志使规则集从顶部重新开始,使用规则集的结果作为起点。使用时要格外小心,因为这可能会导致循环。

例如,如果您希望在请求中重复替换某个字符串或字母,则可以使用[Next]标志。此处显示的示例将在请求中的每个位置将 A 替换为 B,并将 continue 这样做,直到不再有替换的 A。

RewriteRule "(.*)A(.*)" "$1B$2" [N]

您可以将其视为while循环:尽管此模式仍然匹配(即 URI 仍包含A),但是请执行此替换操作(即将A替换为B)。

在 2.4.8 及更高版本中,此模块在 32,000 次迭代后返回错误,以防止意外循环。可以通过添加到 N 标志来指定替代的最大迭代次数。

# Be willing to replace 1 character in each pass of the loop
RewriteRule "(.+)[><;]$" "$1" [N=64000]
# ... or, give up if after 10 loops
RewriteRule "(.+)[><;]$" "$1" [N=10]

NC|nocase

使用[NC]标志会使RewriteRule以不区分大小写的方式进行匹配。也就是说,不在乎字母在匹配的 URI 中是大写还是小写。

在下面的示例中,对图像文件的任何请求都将被代理到您的专用图像服务器。匹配不区分大小写,例如,.jpg.JPG文件都可以接受。

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

NE|noescape

默认情况下,特殊字符(例如&?)将转换为等效的十六进制代码。使用[NE]标志可以防止这种情况的发生。

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

上面的示例会将/anchor/xyz重定向到/bigpage.html#xyz。省略[NE]将导致#转换为等效的十六进制代码%23,然后将导致 404 Not Found 错误情况。

NS|nosubreq

使用[NS]标志可防止将规则用于子请求。例如,使用 SSI(服务器端包含)包含的页面是一个子请求,您可能希望避免在这些子请求上发生重写。另外,当mod_dir尝试查找有关可能的目录默认文件(例如index.html文件)的信息时,这是一个内部子请求,因此您通常希望避免对此类子请求进行重写。如果应用了完整的规则集,则在子请求上,它并不总是有用的,甚至可能导致错误。使用此标志排除有问题的规则。

决定是否使用此规则:如果给 URL 加上 CGI 脚本前缀,以迫使它们由 CGI 脚本处理,则可能会在子请求上遇到问题(或大量开销)。在这些情况下,请使用此标志。

作为 HTML 页面的一部分加载的图像,javascript 文件或 css 文件不是子请求-浏览器将它们作为单独的 HTTP 请求进行请求。

P|proxy

使用[P]标志会使请求由mod_proxy处理,并通过代理请求处理。例如,如果您希望所有图像请求都由后端图像服务器处理,则可以执行以下操作:

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

[P]标志的使用表示[L]-也就是说,该请求将立即通过代理推送,并且不会考虑任何以下规则。

您必须确保替换字符串是有效的 URI(通常以http:// * hostname *开头),可以由mod_proxy处理。如果不是,您将从代理模块收到错误。使用此标志可实现ProxyPass指令的更强大实现,以将远程内容 Map 到本地服务器的名称空间。

Security Warning

在构造规则的目标 URL 时,请小心考虑允许 Client 端影响服务器将用作代理的 URL 集合对安全性的影响。确保 URL 的方案和主机名部分是固定的,或者不允许 Client 端产生不适当的影响。

Performance warning

使用此标志触发使用mod_proxy,而不处理持久连接。这意味着如果您使用ProxyPassProxyPassMatch进行设置,则代理的性能会更好

这是因为此标志触发使用默认工作程序,该默认工作程序不处理连接池/重用。

避免使用此标志,并尽可能使用这些指令。

注意:必须启用mod_proxy才能使用此标志。

PT|passthrough

默认情况下,假定 RewriteRule 中的目标(或替换字符串)为文件路径。使用[PT]标志会使它被视为 URI。也就是说,使用[PT]标志会导致RewriteRule的结果通过 URL Map 传回,因此基于位置的 Map(例如AliasRedirectScriptAlias)可能会生效。

例如,如果您有一个用于/ icons 的Alias并指向其中的RewriteRule,则应使用[PT]标志来确保Alias被求值。

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

在这种情况下省略[PT]标志将导致别名被忽略,从而导致返回“找不到文件”错误。

PT标志表示L标志:重写将停止,以便将请求传递到处理的下一阶段。

请注意,在每个目录的上下文(例如<Directory>部分或.htaccess文件)中都隐含了PT标志。唯一可以避免的方法是重写-

QSA|qsappend

当替换 URI 包含查询字符串时,RewriteRule的默认行为是丢弃现有查询字符串,并将其替换为新生成的查询字符串。使用[QSA]标志会使查询字符串组合在一起。

请考虑以下规则:

RewriteRule "/pages/(.+)" "/page.php?page=$1" [QSA]

使用[QSA]标志,对/pages/123?one=two的请求将 Map 到/page.php?page=123&one=two。如果没有[QSA]标志,则相同的请求将被 Map 到/page.php?page=123-也就是说,现有的查询字符串将被丢弃。

QSD|qsdiscard

当请求的 URI 包含查询字符串而目标 URI 不包含查询字符串时,RewriteRule的默认行为是将该查询字符串复制到目标 URI。使用[QSD]标志会导致查询字符串被丢弃。

此标志在 2.4.0 及更高版本中可用。

一起使用[QSD]和[QSA]将导致[QSD]优先。

如果目标 URI 具有查询字符串,则将遵循默认行为-也就是说,原始查询字符串将被丢弃,并替换为RewriteRule目标 URI 中的查询字符串。

QSL|qslast

默认情况下,替换中的第一个(最左侧)问号会分隔查询字符串的路径。使用[QSL]标志指示RewriteRule使用最后一个(最右边的)问号来拆分两个组件。

当 Map 到文件名中带有 Literals 问号的文件时,这很有用。如果替换中未使用任何查询字符串,则可以与此标志一起附加问号。

此标志在 2.4.19 及更高版本中可用。

R|redirect

使用[R]标志会导致向浏览器发出 HTTP 重定向。如果指定了完全限定的 URL(即包括http://servername/),则将向该位置发出重定向。否则,将使用当前协议,服务器名称和端口号来生成随重定向发送的 URL。

可以使用语法[R = 305]指定*任何有效的 HTTP 响应状态代码,如果未指定,则默认使用 302 状态代码。指定的状态代码不必一定是重定向(3xx)状态代码。但是,如果状态代码在重定向范围(300-399)之外,则替换字符串将完全删除,并且重写将停止,就好像使用了L一样。

除了响应状态代码外,您还可以使用其符号名称指定重定向状态:temp(默认),permanentseeother

您几乎总是希望将[R]与[L]结合使用(即,使用[R,L]),因为[R]标志单独将http://thishost[:thisport]附加到 URI,然后将其传递给 URI。规则集中的下一条规则,通常可能会导致“请求中的 URI 无效”警告。

S|skip

[S]标志用于跳过您不想运行的规则。跳过标志的语法为[S = * N *],其中* N *表示要跳过的规则数(前提是RewriteRule个匹配项)。可以将其视为您的重写规则集中的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>指令来完成这种配置可能更容易。

T|type

设置将发送结果响应的 MIME 类型。与AddType指令具有相同的效果。

例如,如果以特定方式请求,则可以使用以下技术将 Perl 源代码作为纯文本提供:

# Serve .pl files as plain text
RewriteRule "\.pl$" "-" [T=text/plain]

或者,也许,如果您有一台能生成不带文件 extensions 的 jpeg 图像的相机,则可以凭借其文件名来强制为这些图像提供正确的 MIME 类型:

# Files with 'IMG' in the name are jpg images.
RewriteRule "IMG" "-" [T=image/jpg]

请注意,这是一个简单的示例,最好使用<FilesMatch>来完成。在诉诸重写之前,请务必先考虑问题的替代解决方案,这总是比替代方案效率低下。

如果在每个目录的上下文中使用,请仅使用-(破折号)代替进行整个 mod_rewrite 处理,否则,由于内部重新处理(包括后续的回合操作),设置有此标志的 MIME 类型将丢失。 mod_rewrite 处理)。在这种情况下,L标志可用于结束当前的一轮 mod_rewrite 处理。

首页