📄 mod_rewrite+.html
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>Apache HTTP服务器 2.0版本文档</title>
<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" />
</head>
<body>
<div id="preamble"><h1>Apache模块 mod_rewrite</h1>
<table class="module"><tr><th><a href="module-dict.html#Description">说明:</a></th><td>提供了一个基于规则的实时转向URL请求的引擎</td></tr>
<tr><th><a href="module-dict.html#Status">状态:</a></th><td>Extension</td></tr>
<tr><th><a href="module-dict.html#ModuleIdentifier">模块名:</a></th><td>rewrite_module</td></tr>
<tr><th><a href="module-dict.html#SourceFile">源文件:</a></th><td>mod_rewrite.c</td></tr>
<tr><th><a href="module-dict.html#Compatibility">兼容性:</a></th><td>包含在Apache 1.3及其更新版本中</td></tr></table>
<h3>概要</h3>
<blockquote>
<p>``The great thing about mod_rewrite is it gives you
all the configurability and flexibility of Sendmail.
The downside to mod_rewrite is that it gives you all
the configurability and flexibility of Sendmail.''</p>
<p class="cite">-- <cite>Brian Behlendorf</cite><br />
Apache Group</p>
</blockquote>
<blockquote>
<p>`` Despite the tons of examples and docs,
mod_rewrite is voodoo. Damned cool voodoo, but still
voodoo. ''</p>
<p class="cite">-- <cite>Brian Moore</cite><br />
bem@news.cmc.net</p>
</blockquote>
<p>欢迎来到mod_rewrite, URL操作的瑞士军刀!</p>
<p>此模块提供了一个基于规则的(使用正则表达式分析器的)实时转向URL请求的引擎。
支持每个规则可以拥有不限数量的规则以及附加条件规则的灵活而且强大的URL操作机制。
此URL操作可以取决于各种测试,比如服务器变量、环境变量、HTTP头、时间标记,
甚至各种格式的用于匹配URL组成部分的查找数据库。</p>
<p>此模块可以操作URL的所有部分(包括路径信息部分),
在服务器级的(<code>httpd.conf</code>)和目录级的(<code>.htaccess</code>)配置都有效,
还可以生成最终请求串。此重写操作的结果可以是内部子处理,也可以是外部请求的转向,
甚至还可以是内部代理处理。</p>
<p>但是,所有这些功能和灵活性带来一个问题,那就是复杂性,
因此,不要指望一天之内就能看懂整个模块。</p>
<p>此模块从1997年7月起为Apache Group所专用,由以下这些人创建于1996年4月</p>
<p class="indent">
<a href="http://www.engelschall.com/"><code>Ralf S.
Engelschall</code></a><br />
<a href="mailto:rse@engelschall.com"><code>rse@engelschall.com</code></a><br />
<a href="http://www.engelschall.com/"><code>www.engelschall.com</code></a>
</p>
</div>
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="Internal" id="Internal">内部处理</a></h2>
<p>此模块的内部处理极为复杂,但是,为了使一般用户避免犯低级错误,
也让管理员能充分利用其功能,在此仍然做一下说明。</p>
<h3><a name="InternalAPI" id="InternalAPI">API程序段</a></h3>
<p>首先,你必须了解,Apache是通过若干程序段来处理HTTP请求的。
Apache API 对每个程序段提供了一个hook程序。
Mod_rewrite使用两个hook程序:
其一是,URL到文件名的转译hook,用在读取HTTP请求之后,而在授权开始之前;
其二是,修正hook,用在授权程序段和读取目录级配置文件(<code>.htaccess</code>)之后,
而在内容处理器激活之前。</p>
<p>所以,Apache收到一个请求并且确定了响应主机(或者是虚拟主机)之后,
重写引擎即开始执行URL到文件名程序段,以处理服务器级的配置中所有的mod_rewrite指令。
在最终数据目录确定以后,进入修正程序段并触发目录级配置中的mod_rewrite指令。
这两个程序段并不是泾渭分明的,但都实施把URL重写成新的URL或者文件名。
虽然API最初不是为此设计的,但它已经成为API的一种用途,
而在Apache 1.x 中这是mod_rewrite唯一的实现方法。
记住以下两点,会有助于更好地理解:</p>
<ol>
<li>虽然mod_rewrite可以重写URL为URL,重写URL为文件名,
甚至重写文件名为文件名,但是目前API只提供一个URL到文件名的hook。
在Apache 2.0 中,增加了两个丢失hook以使处理过程更清晰。
但是,这样做并没有给用户带来麻烦,只需记住这样一个事实:
Apache借助URL到文件名的hook而比API设计的目标功能更强大。</li>
<li>
难以置信的是,mod_rewrite提供了目录级的URL操作,<em>即</em>,<code>.htaccess</code>文件,
而这些文件必须在URL转换成文件名以后的较多步骤完成之后才会被处理。
这也是必须的,因为<code>.htaccess</code>文件存在于文件系统中,所以处理已经到达这个层面。
换句话说,根据API程序段,这时再处理任何URL操作已经太晚了。
为了解决这个鸡和蛋的问题,mod_rewrite使用了一个技巧:
在进行一个目录级的URL/文件名的操作时,mod_rewrite先把文件名重写回相应的URL
(通常这个操作是不可行的,但是参考下面的<code>RewriteBase</code>指令就明白它是怎么实现的),
然后,对这个新的URL建立一个新的内部的子请求,以此重新开始API程序段的执行。
<p>另外,mod_rewrite尽力使这些复杂的操作对用户全透明,但仍须记住:
服务器级的URL操作速度快而且效率高,而目录级的操作由于这个鸡和蛋的问题速度慢效率也低。
但从另一个侧面看,这却是mod_rewrite得以为一般用户提供(局部限制的)URL操作的唯一方法。</p>
</li>
</ol>
<p>牢记这两点!</p>
<h3><a name="InternalRuleset" id="InternalRuleset">规则集的处理</a></h3>
<p>当mod_rewrite在这两个程序段中开始执行时,它会读取配置结构中的配置好的
(或者是在服务启动时建立的服务器级的,或者是Apache核心在遍历目录采集到的目录级的)规则集,
随后,启动URL重写引擎来处理(带有一个或多个条件)的规则集。
无论是服务器级的还是目录级的规则集,都是由同一个URL重写引擎处理,只是处理结果不同而已。</p>
<p>规则集中规则的顺序是很重要的,因为重写引擎是按一种特殊的(非常规的)顺序处理的,
其原则是:逐个遍历每个规则(<code class="directive"><a href="#rewriterule">RewriteRule</a></code> directives),
如果出现一个匹配条件的规则,则可能回头遍历已有的规则条件(<code>RewriteCond</code>directives)。
由于历史的原因,条件规则是置前的,所以控制流程略显冗长,细节见Figure 1。</p>
<p class="figure">
<img src="../images/mod_rewrite_fig1.gif" width="428" height="385" alt="[Needs graphics capability to display]" /><br />
<dfn>Figure 1:</dfn>The control flow through the rewriting ruleset
</p>
<p>可见,URL首先与每个规则的<em>Pattern</em>匹配,
如果匹配不成功,mod_rewrite立即终止此规则的处理,继而处理下一个规则。
如果匹配成功,mod_rewrite寻找响应的规则条件,如果一个条件都没有,
则简单地用<em>Substitution</em>构造的新的值来替换URL,然后继续处理其他规则。
如果条件存在,则开始一个内部循环按其列出的顺序逐个处理。
对规则的条件的处理有所不同:URL并不与pattern匹配,
而是,首先通过扩展变量、反向引用、查找映射表等步骤建立一个<em>TestString</em>的字符串,
随后,用它来与<em>CondPattern</em>匹配。如果匹配不成功,则整个条件集和对应的规则失败;
如果匹配成功,则执行下一个规则直到所有条件执行完毕。
如果所有条件得以匹配,则以<em>Substitution</em>替换URL,并且继续处理。</p>
<h3><a name="quoting" id="quoting">特殊字符的引用</a></h3>
<p>在Apache 1.3.20, <em>TestString</em> and <em>Substitution</em>
字符串中的特殊字符可以用前缀的斜杠来实现转义(即,忽略其特殊含义而视之为普通字符)。
比如,<em>Substitution</em>可以用'<code>\$</code>'来包含一个美元符号,
以避免mod_rewrite把它视为反向引用。</p>
<h3><a name="InternalBackRefs" id="InternalBackRefs">正则表达式的反向引用能力</a></h3>
<p>这是很重要的一点:一旦在<em>Pattern</em>或者<em>CondPattern</em>使用了圆括号,
就会建立内部的反向引用,可以使用<code>$N</code>和<code>%N</code>来调用(见下述),
并且,在<em>Substitution</em>和<em>TestString</em>中都有效。
Figure 2 说明了反向引用被转换扩展的位置。</p>
<p class="figure">
<img src="../images/mod_rewrite_fig2.gif" width="381" height="179" alt="[Needs graphics capability to display]" /><br />
<dfn>Figure 2:</dfn> The back-reference flow through a rule.
</p>
<p>虽然mod_rewrite内部处理的这个过程是比较杂乱的,
但是了解这些可以帮助你阅读下文中指令的讲述。</p>
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="EnvVar" id="EnvVar">环境变量</a></h2>
<p>此模块会跟踪两个额外的(非标准的)CGI/SSI环境变量,
<code>SCRIPT_URL</code>和<code>SCRIPT_URI</code>。
他们包含了当前资源的<em>逻辑的</em>网络状态,
而标准的CGI/SSI变量<code>SCRIPT_NAME</code>和
<code>SCRIPT_FILENAME</code>包含的是<em>物理的</em>系统状态。</p>
<p>注意: 这些变量保持的是<em>其最初被请求时的</em>URI/URL,
<em>即</em>, 在任何重写操作<em>之前</em>的。
其重要性在于他们是重写操作重写URL到物理路径名的原始依据。</p>
<div class="example"><h3>举例</h3><pre>
SCRIPT_NAME=/sw/lib/w3s/tree/global/u/rse/.www/index.html
SCRIPT_FILENAME=/u/rse/.www/index.html
SCRIPT_URL=/u/rse/
SCRIPT_URI=http://en1.engelschall.com/u/rse/
</pre></div>
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="Solutions" id="Solutions">实用方案</a></h2>
<p>我们还提供另外一个文档<a href="../misc/rewriteguide.html">URL Rewriting Guide</a>,
列举了许多基于URL的问题的实用方案,其中你可以找到真实有用的规则集和mod_rewrite的更多信息。</p>
</div>
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="directive-section"><h2><a name="RewriteBase" id="RewriteBase">RewriteBase</a> <a name="rewritebase" id="rewritebase">指令</a></h2>
<table class="directive">
<tr><th><a href="directive-dict.html#Description">说明:</a></th><td>设置目录级重写的基准URL</td></tr>
<tr><th><a href="directive-dict.html#Syntax">语法:</a></th><td><code>RewriteBase <em>URL-path</em></code></td></tr>
<tr><th><a href="directive-dict.html#Default">默认值:</a></th><td><code>参见使用方法.</code></td></tr>
<tr><th><a href="directive-dict.html#Context">上下文:</a></th><td>目录, .htaccess</td></tr>
<tr><th><a href="directive-dict.html#Override">覆盖项:</a></th><td>FileInfo</td></tr>
<tr><th><a href="directive-dict.html#Status">状态:</a></th><td>Extension</td></tr>
<tr><th><a href="directive-dict.html#Module">模块:</a></th><td>mod_rewrite</td></tr>
</table>
<p><code class="directive">RewriteBase</code>指令显式地设置了目录级重写的基准URL。
在下文中,你可以看见<code class="directive"><a href="#rewriterule">RewriteRule</a></code>可以用于目录级的配置文件中(<code>.htaccess</code>),
并在局部范围内起作用,即,规则实际处理的只是剥离了本地路径前缀的一部分。
处理结束后,这个路径会被自动地附着回去。
默认值是,<code class="directive">RewriteBase</code> <em>physical-directory-path</em></p>
<p>在对一个新的URL进行替换时,此模块必须把这个URL重新注入到服务器处理中。
为此,它必须知道其对应的URL前缀或者说URL基准。通常,此前缀就是对应的文件路径。
<strong>但是,大多数网站URL不是直接对应于其物理文件路径的,因而一般不能做这样的假定!</strong>
所以在这种情况下,就必须用<code>RewriteBase</code>指令来指定正确的URL前缀。</p>
<div class="note">如果你的网站服务器URL<strong>不是</strong>与物理文件路径直接对应的,
而又需要使用<code class="directive"><a href="#rewriterule">RewriteRule</a></code>指令,
则必须在每个对应的<code>.htaccess</code>文件中指定<code class="directive">RewriteBase</code>。
</div>
<p>举例,目录级配置文件内容如下:</p>
<div class="example"><pre>
#
# /abc/def/.htaccess -- per-dir config file for directory /abc/def
# Remember: /abc/def is the physical path of /xyz, <em>i.e.</em>, the server
# has a 'Alias /xyz /abc/def' directive <em>e.g.</em>
#
RewriteEngine On
# let the server know that we were reached via /xyz and not
# via the physical path prefix /abc/def
RewriteBase /xyz
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -