《Apache_URL重写》由会员分享,可在线阅读,更多相关《Apache_URL重写(28页珍藏版)》请在金锄头文库上搜索。
1、URL 重写简介本篇文档是 mod_rewrite 参考文档 的补充,阐述了使用 mod_rewrite 之前必须了解的基本概念。其它文档则作了更加深入的探讨。不过这篇文档对于初学者是一篇很好的入门读物。简介Apache 的 mod_rewrite 是提供了强大 URL 操作的杀手级模块,可以实现几乎所有你梦想的 URL 操作,其代价是你必须接受其复杂性,因为 mod_rewrite 对于初学者的主要障碍就是不容易理解和运用,即使是 Apache专家有时也会发掘出 mod_rewrite 的新用途。换句话说:你或者是打退堂鼓永不再用,或者是喜欢它并一生受用。目前存在这样一种倾向:许多初学者只是
2、把 URL 重写规则当着是会变戏法的魔咒,而并未在使用中真正理解这些规则的含义。本篇文档试图给出充分的背景知识,以便于初学者随后的理解,而不是盲目的复制和粘贴。正则表达式mod_rewrite 使用的是 Perl 兼容的正则表达式语法。本文不打算详细讲解正则表达式语法,你可以到 PCRE man page, Perl regular expression man page, Mastering Regular Expressions, by Jeffrey Friedl 获得这些内容。RewriteRule 指令的说明部分有一个简单的正则表达式语法简介,可以去参考一下。另外需要说明的是可以在表
3、达式的最前面加上一个感叹号(!)表示不匹配,不过这种用法并不符合正则表达式语法。正则表达式的反向引用能力这是很重要的一点:一旦在 Pattern 或者 CondPattern 中使用了圆括号,就会建立内部的反向引用,可以使用$N 和%N 来调用(见下述),并且在 Substitution 和 TestString 中都有效。图-2 说明了反向引用被转换和展开的位置。图 -2: The back-reference flow through a rule. RewriteRule basics(此部分文档尚未完成) Basic anatomy of a RewriteRule, with exh
4、austively annotated simple examples. Rewrite Flags(此部分文档尚未完成) Discussion of the flags to RewriteRule, and when and why one might use them.Rewrite conditions(此部分文档尚未完成) Discussion of RewriteCond, looping, and other related concepts. Rewrite maps(此部分文档尚未完成) Discussion of RewriteMap, including simple,
5、but heavily annotated, examples.htaccess files(此部分文档尚未完成) Discussion of the differences between rewrite rules in httpd.conf and in .htaccess files.环境变量此模块会跟踪两个额外的(非标准)CGI/SSI 环境变量:SCRIPT_URL 和 SCRIPT_URI。他们包含了当前资源的逻辑 网络视图,而标准 CGI/SSI 变量 SCRIPT_NAME 和 SCRIPT_FILENAME 包含的是 物理 系统视图。注意:这些变量保持的是 其最初被请求时的
6、 URI/URL,即在任何重写操作 之前 的 URI/URL。其重要性在于他们是重写操作重写 URL 到物理路径名的原始依据。示例SCRIPT_NAME=/sw/lib/w3s/tree/global/u/rse/.www/index.htmlSCRIPT_FILENAME=/u/rse/.www/index.htmlSCRIPT_URL=/u/rse/SCRIPT_URI=http:/ 重写技术细节本文探讨一些 mod_rewrite 和 URL 匹配的技术细节。内部处理此模块的内部处理极为复杂,但是为了使一般用户避免犯低级错误,也让管理员能充分利用其功能,在此仍然做一下说明。API 阶段首
7、先,你必须了解 Apache 是分若干阶段来处理 HTTP 请求的。Apache API 对每个阶段都提供了一个 hook 程序。mod_rewrite 使用两个 hook 程序:其一,从 URL 到文件名的转换 hook(用在读取 HTTP 请求之后、授权开始之前); 其二,修正 hook(用在授权阶段和读取目录级配置(.htaccess)之后、内容处理器激活之前) 。所以,Apache 收到一个请求并且确定了响应主机( 或虚拟主机)之后,重写引擎即开始处理服务器级配置中的所有 mod_rewrite 指令(此时处于从 URL 到文件名转换的阶段),此阶段完成后,最终的数据目录便确定了。接下
8、来进入修正程序段并触发目录级配置中的 mod_rewrite 指令。这两个阶段并不是泾渭分明的,但都实施了把 URL 重写成新的 URL 或者文件名。虽然 API 最初不是为此目的而设计的,但是现在它已经成为了 API 的一种用途。记住以下两点,会有助于更好地理解:1. 虽然 mod_rewrite 可以将 URL 重写为新的 URL 或文件名,甚至将文件名重写为新的文件名,但是之前的 API 只提供从 URL 到文件名的 hook。在 Apache 2.0 中,增加了两个丢失的hook 以使得处理过程更加清晰。不过这样做并没有给用户带来麻烦,用户只需记住这样一个事实:借助从 URL 到文件名
9、的 hook 比最初 API 设计的目标功能更强大。 2. 令人难以置信的是,mod_rewrite 还提供了目录级的 URL 操作(.htaccess 文件),而这些文件必须在将 URL 转换成文件名之后才会被处理( 这是必须的,因为.htaccess 存在于文件系统中)。换句话说,根据 API 阶段,这时再处理任何 URL 操作已经太晚了。为了解决这个鸡和蛋 的问题,mod_rewrite 使用了一个小技巧:在进行一个目录级的 URL/文件名操作时,先把文件名重写回相应的 URL(通常这个操作是不可行的,但是参考下面的RewriteBase 指令就能明白它是怎么实现的了 ),然后,对这个新
10、的 URL 建立一个新的内部的子请求,再重新开始 API 阶段的执行。 另外,mod_rewrite 尽力使这些复杂的操作对用户透明。但仍须记住:服务器级的 URL 操作速度快而且效率高,而目录级的操作由于这个鸡和蛋的问题速度较慢而且效率也低。但从另一个侧面看,这却是 mod_rewrite 得以为一般用户提供( 局部限制的)URL 操作的唯一方法。牢记这两点!规则集的处理当 mod_rewrite 在这两个 API 阶段中开始执行时,它会读取配置结构中配置好的 (或者是在服务启动时建立的服务器级的,或者是在遍历目录采集到的目录级的)规则集,然后,启动 URL 重写引擎来处理(带有一个或多个条
11、件的)规则集。无论是服务器级的还是目录级的规则集,都是由同一个 URL 重写引擎处理,只是最终结果处理不同而已。规则集中规则的顺序是很重要的,因为重写引擎是按一种特殊的顺序处理的:逐个遍历每个规则(RewriteRule 指令),如果出现一个匹配条件的规则,则可能回头遍历已有的规则条件(RewriteCond 指令)。由于历史的原因,条件规则是前置的,所以控制流程略显冗长,细节见图-1。初级 URL 重写指南本文是 mod_rewrite 参考文档的补充材料。阐述在实际应用中如何解决网管所面临的基于 URL 的典型问题,并详细描述了如何配置 URL 重写规则集以解决这些问题。注意:根据你的服务
12、器配置,有可能必须对这里的例子作些小修改,比如,在额外启用 mod_alias 和mod_userdir 的情况下要增加PT标志,或者为了适应目录级( .htaccess)的配置而将针对服务器级的规则集进行重写。对一个特定的规则集应该先透彻理解然后再考虑应用,这样才能避免出现问题。规范化 URL描述: 在有些 web 服务器上,一个资源会拥有多个 URL。在实际应用和发布中应该使用的是规范的 URL,其他的则是简写或者只在内部使用。无论用户在请求中使用什么形式的 URL,最终看见的都应该是规范的 URL。 解决方案: 对所有不规范的 URL 执行一个外部 HTTP 重定向,以改变它在浏览器地址
13、栏中的显示及其后继请求。下例中的规则集用规范的/u/user 替换/user ,并修正了/u/user 所遗漏的后缀斜杠。 RewriteRule /(/+)/?(.*) /u/$1/$2 RRewriteRule /u/(/+)$ /$1/$2/ R规范化主机名描述: 这个规则的目的是强制使用特定的主机名以代替其他名字。比如,你想强制使用 代替 ,就可以在以下方案的基础上进行修改: 解决方案: 对运行在非 80 端口的站点RewriteCond %HTTP_HOST !fully.qualified.domain.name NCRewriteCond %HTTP_HOST !$Rewrite
14、Cond %SERVER_PORT !80$RewriteRule /(.*) http:/fully.qualified.domain.name:%SERVER_PORT/$1 L,R对运行在 80 端口的站点RewriteCond %HTTP_HOST !fully.qualified.domain.name NCRewriteCond %HTTP_HOST !$RewriteRule /(.*) http:/fully.qualified.domain.name/$1 L,R移动过的 DocumentRoot描述: 通常,web 服务器的 DocumentRoot 直接对应于 URL/,
15、但是它常常不是处于最高的一级。比如,你希望访问者在进入网站时首先进入/about/目录。可以使用下面给出的规则集。 解决方案: 只需将/重定向到 /about/即可: RewriteEngine onRewriteRule /$ /about/ R也可以使用 RedirectMatch 指令解决问题:RedirectMatch /$ http:/ 结尾斜杠问题描述: 每个网管对引用目录的结尾斜杠问题都有一本苦经,如果遗漏了,服务器会产生一个错误,因为如果请求是/quux/foo而不是/quux/foo/,服务器就会去找一个叫 foo 的文件,而它是一个目录,所以就报错了。通常,可以使用这个 FAQ entry 里面提到的方法解决问题。但是有时候需要使用重写规则来解决问题,比如,在应用了许多复杂的重写规则之后。 解决方案: 解决这个微妙问题的方案是让服务器自动添加后缀斜杠。为了达到目的,必须使用一个外部重定向,以使浏览器能够正确地处理后继的请求(比如对图片的请求) 。如果仅仅执行一个内部重写,可能仅仅对目录页面有效,而对含有相对 URL 的图片的页面无效,因为浏览器有请求内嵌目标的可能。比如,如果不用外部重定向,对/quux/foo/index.html 页面中的 image.gif 的请求将变成对/quux/image.gif 的请求!所以,应该这样写: R