Answers:
mod_rewrite
规则可以放在httpd.conf
文件内,也可以放在文件内.htaccess
。如果您可以访问httpd.conf
,则在此处放置规则将带来性能优势(因为规则只处理一次,而不是每次.htaccess
调用文件时都如此)。
可以从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]
标志(请参阅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
不会导致重新解析您的请求的上下文中(即)。
[L]
标志表示规则在当前处理中处于最后状态,因为它们是内部重定向,因此不会停止重写,因此您dirB
将dirC
在下一个htaccess处理中应用该规则。单独RewriteRule ^(.*)$ index.php?query=$1
将内部重定向的无限循环(实际上它是经过10次迭代终止)。-1是因为建议[L]不是last。这不是终止重写过程,而是最后一步。
RewriteCond %{HTTPS} off
是检查HTTPS连接的首选方法(在您的示例中,将非SSL流量强制为HTTPS)
.*
带有[L]
标志的每个问题中建议这样做。
200
,!=200
,^.
,^$
。显然,将变量设置200
为重定向,但其他页面(错误和填充)也将其设置为某个值。现在,这意味着你要么检查,如果它is empty
,is not empty
,is 200
或者is not 200
,这取决于你所需要的。
与RewriteBase的处理:
您几乎总是需要设置RewriteBase。如果您不这样做,则apache会猜测您的基础是目录的物理磁盘路径。因此,从此开始:
RewriteBase /
RewriteBase .
,或者说它应该保持URL不变,只是更改您指定的内容?
RewriteBase
在RewriteRule
指令中使用相对路径替换时才需要设置。最好避免使用相对路径。
RewriteBase
完全避免使用,因为几乎所有开发人员都误解了它的作用。正如@ w3d所说,仅当您要保存字符并希望将同一基数应用于一个文件中的所有RewriteRules时才需要它。如果您避免,您的代码对其他人可能会更清晰。
其他陷阱:
1-有时禁用MultiViews是一个好主意
Options -MultiViews
我不太了解MultiViews的所有功能,但是我知道它在活动时会弄乱我的mod_rewrite规则,因为它的属性之一是尝试“猜测”它认为自己在寻找的文件扩展名。
我将解释:假设您的Web目录中有2个php文件,分别为file1.php和file2.php,并将这些条件和规则添加到.htaccess中:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ file1.php/$1
您假设与文件或目录不匹配的所有url将由file1.php捕获。惊喜!url http:// myhost / file2 / somepath不适用于此规则。相反,您被带到了file2.php内部。
发生的是,MultiViews自动猜测您实际想要的URL是http://myhost/file2.php/somepath,很高兴带您到那里。
现在,您不知道刚刚发生了什么,此时您正在质疑您认为对mod_rewrite知道的一切。然后,您开始尝试使用规则来尝试理解这种新情况背后的逻辑,但是您测试的次数越多,其意义就越小。
好的,总之,如果您希望mod_rewrite以近似逻辑的方式工作,则关闭MultiViews是朝着正确方向迈出的一步。
2-启用FollowSymlinks
Options +FollowSymLinks
那一个,我真的不知道细节,但是我已经看过很多次了,所以就去做。
+FollowSymLinks
mod_rewrite
出于模糊的安全原因,在文档中提到该功能对于所有工作都是必不可少的。
公式可以通过以下示例完成:
RewriteCond %{REQUEST_URI} ^/(server0|server1).*$ [NC]
# %1 is the string that was found above
# %1<>%{HTTP_COOKIE} concatenates first macht with mod_rewrite variable -> "test0<>foo=bar;"
#RewriteCond search for a (.*) in the second part -> \1 is a reference to (.*)
# <> is used as an string separator/indicator, can be replaced by any other character
RewriteCond %1<>%{HTTP_COOKIE} !^(.*)<>.*stickysession=\1.*$ [NC]
RewriteRule ^(.*)$ https://notmatch.domain.com/ [R=301,L]
动态负载平衡:
如果使用mod_proxy平衡系统,则可以添加动态范围的工作服务器。
RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC]
RewriteRule (.*) https://worker%1.internal.com/$1 [P,L]
对[L]标志有更好的理解。[L]标志是最后一个,您只需要了解是什么会导致您的请求再次通过URL解析引擎进行路由。从文档(http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_l)(重点是我的):
[L]标志使mod_rewrite停止处理规则集。在大多数情况下,这意味着如果规则匹配,将不再处理其他规则。这对应于Perl中的最后一个命令,或C中的break命令。使用此标志指示应立即应用当前规则,而不考虑其他规则。
如果要在.htaccess文件或
<Directory>
各节中使用RewriteRule,则一定要对规则的处理方式有所了解。简化的形式是,一旦处理了规则,重写的请求就会交还给 URL解析引擎,以对其进行处理。在处理重写的请求时,<Directory>
可能会再次遇到.htaccess文件或节,因此规则集可能会从头开始再次运行。最常见的情况是,如果其中一个规则导致重定向(内部或外部)导致请求过程重新开始,则将发生这种情况。
因此,[L]标志确实停止处理通过规则集传递的任何其他重写规则。但是,如果标有[L]的规则修改了该请求,并且您位于.htaccess上下文或该<Directory>
节中,则修改后的请求将再次通过URL解析引擎传递回去。而在下一次通过时,这次可能会匹配不同的规则。如果您不了解所发生的情况,则看起来带有[L]标志的第一个重写规则无效。
如果您确实想停止,最好的方法是使用[END]标志(http://httpd.apache.org/docs/current/rewrite/flags.html#flag_end)代替[L]标志规则的所有进一步处理(以及后续的重新解析)。但是,[END]标志仅适用于Apache v2.3.9 +,因此,如果您的v2.2或更低版本,则仅受[L]标志的困扰。在这种情况下,您必须依赖RewriteCond语句来防止在URL解析引擎的后续传递中匹配规则。或者,您必须确保您的RewriteRule位于不会导致重新解析您的请求的上下文中(即httpd.conf)。
另一个强大的功能是rewrite-map-expansions。如果您要处理大量的主机/重写,它们特别有用:
它们就像一个键值替换:
RewriteMap examplemap txt:/path/to/file/map.txt
然后,您可以在规则中使用映射,例如:
RewriteRule ^/ex/(.*) ${examplemap:$1}
有关此主题的更多信息,请参见:
http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#mapfunc
.htaccess
基于-的重写,请忽略此功能。在这种情况下不起作用。
mod_rewrite可以在不更改URL的情况下修改请求处理的各个方面,例如设置环境变量,设置cookie等。这非常有用。
有条件地设置环境变量:
RewriteCond %{HTTP_COOKIE} myCookie=(a|b) [NC]
RewriteRule .* - [E=MY_ENV_VAR:%b]
返回503响应:
RewriteRule
的[R]
标志可以采用非3xx的值,并返回非重定向响应,例如用于管理的停机时间/维护:
RewriteRule .* - [R=503,L]
将返回503响应(本身不是重定向)。
另外,mod_rewrite可以充当mod_proxy的超级接口,因此您可以执行此操作,而不用编写ProxyPass
指令:
RewriteRule ^/(.*)$ balancer://cluster%{REQUEST_URI} [P,QSA,L]
意见:使用RewriteRule
s和RewriteCond
s根据请求的几乎任何可能的方面将请求路由到不同的应用程序或负载均衡器,功能非常强大。控制返回后端的请求,并能够修改返回的响应,使mod_rewrite成为集中所有与路由相关的配置的理想场所。
花时间学习它,这是值得的!:)