Posts Tagged ‘mod_rewrite’

 今天学习重写规则的语法。 RewriteRuleSyntax: RewriteRule Pattern Substitution [flags]   一条RewriteRule指令,定义一条重写规则,规则间的顺序非常重要。对Apache1.2及以后的版本,模板(pattern)是一个POSIX正则式,用以匹配当前的URL。当前的URL不一定是用记最初提交的URL,因为可能用一些规则在此规则前已经对URL进行了处理。  对mod_rewrite来说,!是个合法的模板前缀,表示“非”的意思,这对描述“不满足某种匹配条件”的情况非常方便,或用作最后一条默认规则。当使用!时,不能在模板中有分组的通配符,也不能做后向引用。  当匹配成功后,Substitution会被用来替换相应的匹配,它除了可以是普通的字符串以外,还可以包括: $N,引用RewriteRule模板中匹配的相关字串,N表示序号,N=0..9 %N,引用最后一个RewriteCond模板中匹配的数据,N表示序号 %{VARNAME},服务器变量 ${mapname:key|default},映射函数调用 这些特殊内容的扩展,按上述顺序进行。  一个URL的全部相关部分都会被Substitution替换,而且这个替换过程会一直持续到所有的规则都被执行完,除非明确地用L标志中断处理过程。  当susbstitution有”-”前缀时,表示不进行替换,只做匹配检查。  利用RewriteRule,可定义含有请求串(Query String)的URL,此时只需在Sustitution中加入一个?,表示此后的内容放入QUERY_STRING变量中。如果要清空一个QUERY_STRING变量,只需要以?结束Substitution串即可。  如果给一个Substitution增加一个http://thishost[:port]的前缀,则mod_rewrite会自动将此前缀去掉。因此,利用http://thisthost做一个无条件的重定向到自己,将难以奏效。要实现这种效果,必须使用R标志。  Flags是可选参数,当有多个标志同时出现时,彼此间以逗号分隔。 ‘redirect|R [=code]‘ (强制重定向)  给当前的URI增加前缀http://thishost[:thisport]/, 从而生成一个新的URL,强制生成一个外部重定向(external redirection,指生的URL发送到客户端,由客户端再次以新的URL发出请求,虽然新URL仍指向当前的服务器). 如果没有指定的code值,则HTTP应答以状态值302 (MOVED TEMPORARILY),如果想使用300-400(不含400)间的其它值可以通过在code的位置以相应的数字指定,也可以用标志名指定: temp (默认值), permanent, seeother.  注意,当使用这个标志时,要确实substitution是个合法的URL,这个标志只是在URL前增加http://thishost[:thisport]/前缀而已,重写操作会继续进行。如果要立即将新URL重定向,用L标志来中重写流程。 ‘forbidden|F’ (强制禁止访问URL所指的资源)  立即返回状态值403 (FORBIDDEN)的应答包。将这个标志与合适的RewriteConds 联合使用,可以阻断访问某些URL。 ‘gone|G’ (强制返回URL所指资源为不存在(gone))  立即返回状态值410 (GONE)的应答包。用这个标志来标记URL所指的资源永久消失了. # ‘proxy|P’ (强制将当前URL送往代理模块(proxy module))  这个标志,强制将substitution当作一个发向代理模块的请求,并立即将共送往代理模块。因此,必须确保substitution串是一个合法的URI (如, 典型的情况是以http://hostname开头),否则会从代理模块得到一个错误. 这个标志,是ProxyPass指令的一个更强劲的实现,将远程请求(remote stuff)映射到本地服务器的名字空间(namespace)中来。  注意,使用这个功能必须确保代理模块已经编译到Apache 服务器程序中了. 可以用“httpd -l ”命令,来检查输出中是否含有mod_proxy.c来确认一下。如果没有,而又需要使用这个功能,则需要重新编译“httpd”程序并使用mod_proxy有效。 ‘last|L’ (最后一条规则)  中止重写流程,不再对当前URL施加更多的重写规则。这相当于perl的last命令或C的break命令。 ‘next|N’ (下一轮)  重新从第一条重写规则开始执行重写过程,新开的过程中的URL不应当与最初的URL相同。 这相当于Perl的next命令或C的continue命令. 千万小心不要产生死循环。 # ‘chain|C’ (将当前的规则与其后续规则綑绑(chained))  当规则匹配时,处理过程与没有綑绑一样;如果规则不匹配,则綑绑在一起的后续规则也不在检查和执行。 ‘type|T=MIME-type’ (强制MIME类型)  强制将目标文件的MIME-type为某MIME类型。例如,这可用来模仿mod_alias模块对某目录的ScriptAlias指定,通过强制将该目录下的所有文件的类型改为 [...]

  车东很早就写了一篇文章来介绍利用mod_rewrite模块来达到用静态页面形式的链接隐藏后台的动态页面。  Apache的rewrite模块,提供了一个基于规则的重写(rewrite,也许译为重构更为合适)引擎,来实时重写发送到Apache的请求URL。因功能极其强大,被称为URL重写的“瑞士军刀”。   这个模块使用一个基于正则表达式解析器开发的重写引擎,根据web管理员定义的规则来实时(on the fly)重写请求URL。它支持任意数目的重写规则,以及附加到一条规则上的任意数目的规则条件,从而提供了一套非常灵活和功能强大的URL处理机制。URL处理操作的实施与否,依赖于各种各样的条件检查,如检查服务器变量、环境变量、HTTP头字段、时间戳的值,甚至外部数据库的检索结果。这个模块可以在服务器范围内(http.conf)、目录范围内(.htaccess)或请求串(query-string)的一部分处理有关的URL。重写的结果URL,可以指向一个站内的处理程序、指向站外的重定向或者一个站内的代理。与灵活和功能强大相随的是设置的复杂,别指望一天内弄明白整个模块。(所以,这个学习笔记也分了几部分:)   内部处理过程 API阶段  首先,Apache处理HTTP请求是分阶段进行的,Apache API为每个阶段提供了一个钩子(hook)。Mod_rewrite使用了其中的两个钩子:一个用来在HTTP请求被读取但还没有访问授权验证之前进行URL_to_filename转换,一个用来在授权验证完成且目录设置文件(.htaccess)读取之后、但内容处理器(content handler)被调用之前激化,进行修补(fixup).因此,当一个请求到达,Apache决定了相关的服务器(或虚拟服务器)以后进行URL_to_filename阶段,重写引擎(rewrite engine)开始处理服务器设置中的重写指令(mod_rewrite directives).接下来几个阶段过后进入修补阶段,此时最终的数据所在的物理目录已经找到,目录配置中的重写指令开始执行。在这两个阶段,mod_rewrite都是将URL重写为新的URL或文件名,所以看起来并没有明显的区别。对API的这种应用,并不是一开始就是这样设计的,而是Apache1.x不得已而为之。为了搞清这个问题,以下两点需要记住。  1)虽然mod_rewrite能进行URL到URL、URL到文件名字甚至文件名字到文件名字的转换,API(1.x)目前提供了一个URL_to_filename转换。在Apache2.0中,这两个钩子会被加进去,整个过程会更加清晰。一个事实必须清楚的记得:Apache在URL_to_filename钩子中,做得比API设计的功能更多。  2)不可思议的是,mod_rewrite能在目录范围内(如根据.htaccess文件的指令配置)进行URL处理,虽然URL很早就已经被转换为文件名字了。只所以会如此,是因为.htaccess文件存在于文件系统中。也就是说,在这个阶段来进行URL处理,是非常晚的时候了。为了解决这个"先有鸡还是先有蛋"的问题,mod_rewrite用了一个小技巧:当在目录范围内处理URL/filename时,mod_rewrite先将文件名逆转回相关的URL(虽然通常是不可能的,但请参见下面用以实现这个技巧的RewriteBase指令),然后据这个新URL生成一个站内的子请求(internal sub-request),这又重开始了API进程。Mod_rewrite尽量使这些复杂的步骤对用户透明,但应要记住:虽然目录范围URL的真正处理过程很快很高效,但这一阶段会因为这个"鸡和蛋"的问题而变得很慢和低效。从另一方面来看,这也是mod_rewrite提供给普通用户进行目录范围内的URL处理的唯一途径.规则集(RewriteRule指令集合)处理过程  当mod_rewrite在上述的两个API阶段被激活时,它会从它的配置数据结构(在开始服务器上下文(per-server context)或目录上下文(per-directory context)时创建的)中读取配置的规则集,然后URL重写引擎启动来执行包含的规则集(一个或多条规则以及它们的条件)。两种上下文中的处理过程都是一样的,差别只是在最后的结果处理过程上。  规则集中规则的顺序是非常重要的,因为重写引擎以特定的顺序来处理它们。重写引擎顺序遍历规则集,当一条规则匹配时,引擎会去遍历与它相关的条件集(RewriteCond指令集合).由于历史的原因,条件集先被列出来,因此控制流流程有点曲折(long-winded).如图一所示:  正如所看到的,首先URL会与每条规则的模板(pattern)比较,当匹配失败时,立即停止对当前规则的处理进入下一条规则。当匹配成功时,mod_rewrite寻找相关的规则条件。如果找不到相关的条件,则直接执行规则中定义的替换,然后回到规则遍历的过程。如果找到了相关的条件,则启动一个内部循环,依次检查各个条件。对于检查,我们不是拿一个模板来匹配当前的URL,而是先创建一个TestString串,将串内的变量、后向引用(bakc-reference)、查询结果(map lookups)等展开,然后用这个TestString和条件式中的CondPattern进行匹配,如果匹配失败,则整个条件集且这个规则都不再执行,重要回到规则遍历中;如果匹配成功,则检查下一个条件,如果所有的条件都满足,则执行规则中定义的替换动作。  特殊字符的转义  既然基于正则式,则当然会有特殊字符的问题。在1.3.20版本的Apache中,通过在特殊字符前加一个“”来将TestString或Sustitution串的特殊字符转义。正则式的后向引用  有一点需要记住:一旦在模板(pattern)或条件模板(CondPattern)中使用了括号,则后向引用已经自动产生了,你可以在Sustitution或TestString中通过$N或%N来引用相关的值。如图,描述了后向引用的值可以传到的位置。 配置指令(Configuration Directives) 指令 语法 默认值 说明 备注 RewriteEngine RewriteEngine on|off Off 开关重构引擎 默认时不能继承,故每个虚拟主机都要有自己的开关指令。 RewriteOptions RewriteOptions Option MaxRedirects=10 设置一些特殊参数 inherit:配置是否继承,MaxRedirects=number:内部重定向次数 RewriteLog RewriteLog file-path None 设定重写log文件 用RewriteLogLevel 0来禁止日志 RewriteLogLevel RewriteLogLevel Level RewriteLogLevel 0 设置日志级别 0表示没有,2以上用于debug,9及以上表示全部信息 RewriteLock RewriteLock file-path None 设置RewriteMap程序的同步锁文件 要求是本地文件,此文件只对rewriting map-program有效。 RewriteMap [...]