最近似乎有相当数量的 mod_rewrite
线程在流动,但对其某些方面的工作原理有些困惑。因此,我编写了一些关于常见功能的注释,也许还有一些令人讨厌的细微差别。
您在使用 mod_rewrite
时还遇到过哪些其他功能/常见问题?
最佳答案
在哪里放置 mod_rewrite 规则
mod_rewrite
规则可以放在 httpd.conf
内文件,或在.htaccess
内文件。如果您有权访问httpd.conf
,将规则放在此处将提供性能优势(因为规则只处理一次,而不是每次调用 .htaccess
文件时处理)。
记录 mod_rewrite 请求
可以从 httpd.conf
内启用日志记录文件(包括 <Virtual Host>
):
# logs can't be enabled from .htaccess
# loglevel > 2 is really spammy!
RewriteLog /path/to/rewrite.log
RewriteLogLevel 2
常见用例
将所有请求集中到一个点:
RewriteEngine on # ignore existing files RewriteCond %{REQUEST_FILENAME} !-f # ignore existing directories RewriteCond %{REQUEST_FILENAME} !-d # map requests to index.php and append as a query string RewriteRule ^(.*)$ index.php?query=$1
自 Apache 2.2.16 起,您还可以使用
FallbackResource
.处理 301/302 重定向:
RewriteEngine on # 302 Temporary Redirect (302 is the default, but can be specified for clarity) RewriteRule ^oldpage\.html$ /newpage.html [R=302] # 301 Permanent Redirect RewriteRule ^oldpage2\.html$ /newpage.html [R=301]
注意:外部重定向是隐式的 302 重定向:
# this rule: RewriteRule ^somepage\.html$ http://google.com # is equivalent to: RewriteRule ^somepage\.html$ http://google.com [R] # and: RewriteRule ^somepage\.html$ http://google.com [R=302]
强制使用 SSL
RewriteEngine on RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://example.com/$1 [R,L]
常用标志:
-
[R]
或[redirect]
- 强制重定向(默认为 302 临时重定向) -
[R=301]
或[redirect=301]
- 强制 301 永久重定向 -
[L]
或[last]
- 停止重写过程(请参阅下面常见陷阱的注释) -
[NC]
或[nocase]
- 指定匹配不区分大小写
使用长格式的标志通常更具可读性,并且会帮助其他人稍后阅读您的代码。您可以用逗号分隔多个标志:
RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
-
常见陷阱
混合
mod_alias
样式重定向为mod_rewrite
# Bad Redirect 302 /somepage.html http://example.com/otherpage.html RewriteEngine on RewriteRule ^(.*)$ index.php?query=$1 # Good (use mod_rewrite for both) RewriteEngine on # 302 redirect and stop processing RewriteRule ^somepage.html$ /otherpage.html [R=302,L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # handle other redirects RewriteRule ^(.*)$ index.php?query=$1
注意:您可以混合
mod_alias
与mod_rewrite
,但它涉及的工作不仅仅是处理上面的基本重定向。上下文影响语法
在
.htaccess
内文件中,RewriteRule 模式中不使用前导斜杠:# given: GET /directory/file.html # .htaccess # result: /newdirectory/file.html RewriteRule ^directory(.*)$ /newdirectory$1 # .htaccess # result: no match! RewriteRule ^/directory(.*)$ /newdirectory$1 # httpd.conf # result: /newdirectory/file.html RewriteRule ^/directory(.*)$ /newdirectory$1 # Putting a "?" after the slash will allow it to work in both contexts: RewriteRule ^/?directory(.*)$ /newdirectory$1
[L] 不是最后一个! (有时)
[L]
标志停止处理任何进一步的重写规则通过规则集。但是,如果 URL 在该过程中被修改,并且您位于.htaccess
上下文或<Directory>
部分,那么你修改后的请求将再次通过 URL 解析引擎传回。而在下一次传递时,这次可能会匹配不同的规则。如果你不明白这一点,它通常看起来像你的[L]
标志没有效果。# processing does not stop here RewriteRule ^dirA$ /dirB [L] # /dirC will be the final result RewriteRule ^dirB$ /dirC
我们的重写日志显示规则运行了两次并且 URL 更新了两次:
rewrite 'dirA' -> '/dirB' internal redirect with /dirB [INTERNAL REDIRECT] rewrite 'dirB' -> '/dirC'
解决这个问题的最佳方法是使用
[END]
标志( see Apache docs )而不是[L]
标志,如果您确实想停止规则的所有进一步处理(以及后续传递)。然而,[END]
标志仅适用于 Apache v2.3.9+,因此,如果您有 v2.2 或更低版本,则只能使用[L]
旗帜。对于早期版本,您必须依赖
RewriteCond
防止 URL 解析引擎后续传递中的规则匹配的语句。# Only process the following RewriteRule if on the first pass RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteRule ...
或者您必须确保您的 RewriteRule 所在的上下文(即
httpd.conf
)不会导致您的请求被重新解析。
关于apache - mod_rewrite 的隐藏功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/286004/