mod_rewrite 的隐藏功能 [英] Hidden features of mod_rewrite
问题描述
最近似乎有相当多的 mod_rewrite
线程在四处流动,但对其某些方面的工作方式有些困惑.因此,我整理了一些关于常见功能的笔记,也许还有一些烦人的细微差别.
There seem to be a decent number of mod_rewrite
threads floating around lately with a bit of confusion over how certain aspects of it work. As a result I've compiled a few notes on common functionality, and perhaps a few annoying nuances.
您在使用 mod_rewrite
时遇到过哪些其他功能/常见问题?
What other features / common issues have you run across using mod_rewrite
?
推荐答案
在哪里放置 mod_rewrite 规则
mod_rewrite
规则可以放在 httpd.conf
文件中,也可以放在 .htaccess
文件中.如果您有权访问 httpd.conf
,在此处放置规则将提供性能优势(因为规则只处理一次,而不是每次调用 .htaccess
文件时).
Where to place mod_rewrite rules
mod_rewrite
rules may be placed within the httpd.conf
file, or within the .htaccess
file. if you have access to httpd.conf
, placing rules here will offer a performance benefit (as the rules are processed once, as opposed to each time the .htaccess
file is called).
可以从 httpd.conf
文件(包括
)中启用日志记录:
Logging may be enabled from within the httpd.conf
file (including <Virtual Host>
):
# logs can't be enabled from .htaccess
# loglevel > 2 is really spammy!
RewriteLog /path/to/rewrite.log
RewriteLogLevel 2
常见用例
将所有请求集中到一个点:
To funnel all requests to a single point:
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
.
Since Apache 2.2.16 you can also use FallbackResource
.
处理 301/302 重定向:
Handling 301/302 redirects:
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 重定向:
Note: external redirects are implicitly 302 redirects:
# 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
Forcing SSL
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/$1 [R,L]
常见标志:
Common flags:
[R]
或[redirect]
- 强制重定向(默认为 302 临时重定向)[R=301]
或[redirect=301]
- 强制 301 永久重定向[L]
或[last]
- 停止重写过程(见下面常见陷阱的注释)[NC]
或[nocase]
- 指定匹配不区分大小写
[R]
or[redirect]
- force a redirect (defaults to a 302 temporary redirect)[R=301]
or[redirect=301]
- force a 301 permanent redirect[L]
or[last]
- stop rewriting process (see note below in common pitfalls)[NC]
or[nocase]
- specify that matching should be case insensitive
使用长格式的标志通常更具可读性,有助于其他人稍后阅读您的代码.
Using the long-form of flags is often more readable and will help others who come to read your code later.
您可以用逗号分隔多个标志:
You can separate multiple flags with a comma:
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
混合使用,但它涉及的工作不仅仅是处理上述基本重定向.
Note: you can mix mod_alias
with mod_rewrite
, but it involves more work than just handling basic redirects as above.
上下文影响语法
在 .htaccess
文件中,RewriteRule 模式中不使用前导斜杠:
Within .htaccess
files, a leading slash is not used in the RewriteRule pattern:
# 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] is not last! (sometimes)
[L]
标志停止处理任何进一步的重写规则通过规则集.但是,如果 URL 在该传递中被修改并且您在 .htaccess
上下文或
部分,那么您修改后的请求将被传递再次通过 URL 解析引擎返回.而在下一次通过时,它这次可能会匹配不同的规则.如果您不理解这一点,通常看起来您的 [L]
标志没有效果.
The [L]
flag stops processing any further rewrite rules for that pass through the rule set. However, if the URL was modified in that pass and you're in the .htaccess
context or the <Directory>
section, then your modified request is going to be passed back through the URL parsing engine again. And on the next pass, it may match a different rule this time. If you don't understand this, it often looks like your [L]
flag had no effect.
# processing does not stop here
RewriteRule ^dirA$ /dirB [L]
# /dirC will be the final result
RewriteRule ^dirB$ /dirC
我们的重写日志显示规则运行了两次并且 URL 更新了两次:
Our rewrite log shows that the rules are run twice and the URL is updated twice:
rewrite 'dirA' -> '/dirB'
internal redirect with /dirB [INTERNAL REDIRECT]
rewrite 'dirB' -> '/dirC'
解决此问题的最佳方法是使用 [END]
标志 (查看 Apache 文档) 而不是 [L]
标志,如果你真的想停止所有进一步的规则处理(和后续的传递).但是,[END]
标志仅适用于 Apache v2.3.9+,因此如果您使用的是 v2.2 或更低版本,则只能使用 [L]
标志.
The best way around this is to use the [END]
flag (see Apache docs) instead of the [L]
flag, if you truly want to stop all further processing of rules (and subsequent passes). However, the [END]
flag is only available for Apache v2.3.9+, so if you have v2.2 or lower, you're stuck with just the [L]
flag.
对于早期版本,您必须依靠 RewriteCond
语句来防止 URL 解析引擎后续传递的规则匹配.
For earlier versions, you must rely on RewriteCond
statements to prevent matching of rules on subsequent passes of the URL parsing engine.
# Only process the following RewriteRule if on the first pass
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ...
或者您必须确保您的 RewriteRule 位于不会导致您的请求被重新解析的上下文(即 httpd.conf
)中.
Or you must ensure that your RewriteRule's are in a context (i.e. httpd.conf
) that will not cause your request to be re-parsed.
这篇关于mod_rewrite 的隐藏功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!