Apache URL重写规则

Apache URL重写规则

 
 


一、简介

  Apached的重写功能,便是mod_rewrite模块功能,它是apache的一个模块。它的功能很是强大,能够操做URL中的全部部分。css

  所以咱们就能够改写url,给用户提供一个简介大方的url,当用户访问时能够经过mod_rewrite模块功能转换为真正的资源路径。经过mod_rewrite能实现的功能还有不少,例如隐藏真实地址、实现URL跳转、域名跳转、防盗链、限制访问资源类型等等。html

 

二、工做流程

  mod_rewrite模块在运行时会使用两个Hook程序。正则表达式

  第一个是从URL到文件名转换的Hook。当有访问到达Apache服务器的时,服务器会确认相应主机(或虚拟主机),这时mod_rewrite模块就开始工做,它将会先处理服务器全局中mod_rewrite模块所提供的指令,而后根据用户提供的指令进行改写。apache

  第二个是修正URL的Hook。在此阶段mod_rewrite模块会处理非全局的设置。例如,目录中的.htaccess文件中的设置。可是此时已经完成URL的翻译(由URL转换为文件名),所以是没法在次对目录级别的URL进行改写操做,可是moe_rewrite模块会将已翻译的URL再次转换为URL的状态,继续进行目录级别的URL改写。(mod_rewrite模块将会使用读后请求阶段的回叫函数从新开始一个请求的循环处理)api

Rewirte模块规则集的处理浏览器

  当mod_rewrite在这两个API阶段中开始执行时,它会读取配置结构中配置好的 (或者是在服务启动时创建的服务器级的,或者是在遍历目录采集到的目录级的)规则集,而后,启动URL重写引擎来处理(带有一个或多个条件的)规则集。不管是服务器级的仍是目录级的规则集,都是由同一个URL重写引擎处理,只是最终结果处理不一样而已。php框架

  规则集中规则的顺序是很重要的,由于重写引擎是按一种特殊的顺序处理的:逐个遍历每一个规则(RewriteRule指令),若是出现一个匹配条件的规则,则可能回头遍历已有的规则条件(RewriteCond指令)。因为历史的缘由,条件规则是前置的,因此控制流程略显冗长,细节见图-1。安全

  可见,URL首先与每一个规则的Pattern匹配,若是匹配失败,mod_rewrite将当即终止此规则的处理,继而处理下一个规则。若是匹配成功,mod_rewrite将寻找相应的规则条件,若是一个条件都没有,则简单地用Substitution构造的新值来替换URL,而后继续处理其余规则;可是若是条件存在,则开始一个内部循环按其列出的顺序逐个处理。对规则条件的处理有所不一样:URL并不与模式进行匹配,而是首先经过扩展变量、反向引用、查找映射表等步骤创建一个TestString字符串,而后用它来与CondPattern匹配。若是匹配失败,则整个条件集和对应的规则失败;若是匹配成功,则执行下一个规则直到全部条件执行完毕。若是全部条件得以匹配,则以Substitution替换URL,而且继续处理。(本部分引用译者:金步国)服务器

网络图片:

 

三、URL重写指令

  最简单的重写指令能够简单到让你没法想象!

  只须要两步就能够完成了。第一使用RewriteEngine开启mod_rewrite模块功能;第二经过RewriteRule定义URL重写规则

 

  1)、URL重写指令套路

复制代码
1 ---------------------------------------------------------------
2 RewriteEngine on   #开启mod_rewrite模块功能
3 RewriteBase 路径     #基准URL(使用alias设置别名则需使用这个)
4 RewriteCond TestString CondPattern [flags]      #重写条件(能够多个)
5 RewriteRule Pattern Substitution [flags]          #重写规则
6 ----------------------------------------------------------------
7 #四、5行能够能够多个
8 #按顺序一个一个执行RewriteRule([flags不终止状况下])
9 ##以上是经常使用的指令,还有一些不多见的指令,须要的本身去查资料了解
复制代码


  2)、RewriteRule Pattern Substitution [flags]

  一、pattern是做用于当前URL的perl兼容的正则表达式。当前URL是指该规则生效时刻的URL的值。它可能与被请求时的URL大相径庭,由于以前可能被其余RewriteRule或者alias指令修改过。

  二、Substitution是当URL与Pattern匹配成功后。用来代替的字符串。

  • 能够对pattern反向引用$N(N=0~9),表示正则表达式中第N个括号中的内容
  • 对最后匹配的RewriteCond反向引用%N(N=0~9),表示最后匹配的RewriteCond第N对括号中的内容
  • 服务器变量%{VARNAME}
  • 映射函数调用${mapname:key|default} (经过RewriteMap指令定义映射辅助完成)

  三、[flags],标志符,多个则用逗号隔开。

标志符(摘抄于网上):

redirect|R [=code] (强制重定向 redirect)

  以 http://thishost[:thisport]/(使新的URL成为一个URI) 为前缀的Substitution能够强制性执行一个外部重定向。 若是code没有指定,则产生一个HTTP响应代码302(临时性移动)。若是须要使用在300-400范围内的其余响应代码,只需在此指定这个数值便可, 另外,还可使用下列符号名称之一: temp (默认的), permanent, seeother. 用它能够把规范化的URL反馈给客户端,如, 重写“/~”为 “/u/”,或对/u/user加上斜杠,等等。

注意: 在使用这个标记时,必须确保该替换字段是一个有效的URL! 不然,它会指向一个无效的位置! 而且要记住,此标记自己只是对URL加上 http://thishost[:thisport]/的前缀,重写操做仍然会继续。一般,你会但愿中止重写操做而当即重定向,则还须要使用’L’标记.

forbidden|F (强制URL为被禁止的 forbidden)

  强制当前URL为被禁止的,即,当即反馈一个HTTP响应代码403(被禁止的)。使用这个标记,能够连接若干RewriteConds以有条件地阻塞某些URL。

gone|G(强制URL为已废弃的 gone)

  强制当前URL为已废弃的,即,当即反馈一个HTTP响应代码410(已废弃的)。使用这个标记,能够标明页面已经被废弃而不存在了.

proxy|P (强制为代理 proxy)

  此标记使替换成分被内部地强制为代理请求,并当即(即, 重写规则处理当即中断)把处理移交给代理模块。你必须确保此替换串是一个有效的(好比常见的以 http://hostname开头的)可以为Apache代理模块所处理的URI。使用这个标记,能够把某些远程成分映射到本地服务器名称空间, 从而加强了ProxyPass指令的功能。

注意: 要使用这个功能,代理模块必须编译在Apache服务器中。 若是你不能肯定,能够检查“httpd -l”的输出中是否有mod_proxy.c。 若是有,则mod_rewrite可使用这个功能;若是没有,则必须启用mod_proxy并从新编译“httpd”程序。

last|L (最后一个规则 last)

  当即中止重写操做,并再也不应用其余重写规则。 它对应于Perl中的last命令或C语言中的break命令。这个标记能够阻止当前已被重写的URL为其后继的规则所重写。 举例,使用它能够重写根路径的URL(’/’)为实际存在的URL, 好比, ‘/e/www/’.

next|N (从新执行 next round)

  从新执行重写操做(从第一个规则从新开始). 这时再次进行处理的URL已经不是原始的URL了,而是经最后一个重写规则处理的URL。它对应于Perl中的next命令或C语言中的continue命令。 此标记能够从新开始重写操做,即, 当即回到循环的头部。
可是要当心,不要制造死循环!

chain|C (与下一个规则相连接 chained)

  此标记使当前规则与下一个(其自己又能够与其后继规则相连接的, 并能够如此反复的)规则相连接。 它产生这样一个效果: 若是一个规则被匹配,一般会继续处理其后继规则, 即,这个标记不起做用;若是规则不能被匹配,则其后继的连接的规则会被忽略。好比,在执行一个外部重定向时, 对一个目录级规则集,你可能须要删除“.www” (此处不该该出现“.www”的)。

type|T=MIME-type(强制MIME类型 type)

  强制目标文件的MIME类型为MIME-type。 好比,它能够用于模拟mod_alias中的ScriptAlias指令,之内部地强制被映射目录中的全部文件的MIME类型为“application/x-httpd-cgi”。

nosubreq|NS (仅用于不对内部子请求进行处理 no internal sub-request)

  在当前请求是一个内部子请求时,此标记强制重写引擎跳过该重写规则。好比,在mod_include试图搜索可能的目录默认文件(index.xxx)时, Apache会内部地产生子请求。对子请求,它不必定有用的,并且若是整个规则集都起做用,它甚至可能会引起错误。因此,能够用这个标记来排除某些规则。

  根据你的须要遵循如下原则: 若是你使用了有CGI脚本的URL前缀,以强制它们由CGI脚本处理,而对子请求处理的出错率(或者开销)很高,在这种状况下,可使用这个标记。

nocase|NC (忽略大小写 no case)

  它使Pattern忽略大小写,即, 在Pattern与当前URL匹配时,’A-Z’ 和’a-z’没有区别。

qsappend|QSA (追加请求串 query string append)

  此标记强制重写引擎在已有的替换串中追加一个请求串,而不是简单的替换。若是须要经过重写规则在请求串中增长信息,就可使用这个标记。

noescape|NE (在输出中不对URI做转义 no URI escaping)

  此标记阻止mod_rewrite对重写结果应用常规的URI转义规则。 通常状况下,特殊字符(如’%’, ‘$’, ‘;’等)会被转义为等值的十六进制编码。 此标记能够阻止这样的转义,以容许百分号等符号出如今输出中,如:

  RewriteRule /foo/(.*) /bar?arg=P1=$1 [R,NE] 可使’/foo/zed’转向到一个安全的请求’/bar?arg=P1=zed’.

passthrough|PT (移交给下一个处理器 pass through)

  此标记强制重写引擎将内部结构request_rec中的uri字段设置为 filename字段的值,它只是一个小修改,使之能对来自其余URI到文件名翻译器的 Alias,ScriptAlias, Redirect 等指令的输出进行后续处理。举一个能说明其含义的例子:若是要经过mod_rewrite的重写引擎重写/abc为/def,而后经过mod_alias使/def转变为/ghi,能够这样:

RewriteRule ^/abc(.*) /def$1 [PT]

Alias /def /ghi
  若是省略了PT标记,虽然mod_rewrite运做正常, 即, 做为一个使用API的URI到文件名翻译器,它能够重写uri=/abc/…为filename=/def/…,可是,后续的mod_alias在试图做URI到文件名的翻译时,则会失效。

注意: 若是须要混合使用不一样的包含URI到文件名翻译器的模块时, 就必须使用这个标记。。混合使用mod_alias和mod_rewrite就是个典型的例子。

For Apache hackers

  若是当前Apache API除了URI到文件名hook以外,还有一个文件名到文件名的hook, 就不须要这个标记了! 可是,若是没有这样一个hook,则此标记是惟一的解决方案。 Apache Group讨论过这个问题,并在Apache 2.0 版本中会增长这样一个hook。

skip|S=num (跳事后继的规则 skip)

  此标记强制重写引擎跳过当前匹配规则后继的num个规则。 它能够实现一个伪if-then-else的构造: 最后一个规则是then从句,而被跳过的skip=N个规则是else从句. (它和’chain|C’标记是不一样的!)

env|E=VAR:VAL (设置环境变量 environment variable)

  此标记使环境变量VAR的值为VAL, VAL能够包含可扩展的反向引用的正则表达式$N和%N。 此标记能够屡次使用以设置多个变量。这些变量能够在其后许多状况下被间接引用,但一般是在XSSI (via ) or CGI (如 $ENV{’VAR’})中, 也能够在后继的RewriteCond指令的pattern中经过%{ENV:VAR}做引用。使用它能够从URL中剥离并记住一些信息。

cookie|CO=NAME:VAL:domain[:lifetime[:path]] (设置cookie)

  它在客户端浏览器上设置一个cookie。 cookie的名称是NAME,其值是VAL。 domain字段是该cookie的域,好比’.apache.org’, 可选的lifetime是cookie生命期的分钟数,可选的path是cookie的路径。



  3)、RewriteCond TestString CondPattern [flags]

  Rewritecond指令定义一条规则条件。在一条rewriterule指令前面可能会有一条或者多条rewritecond指令,只有当自身模板匹配成功且这些条件也知足时(即RewriteRule中的pattern匹配成功),规则条件才被应用于当前URL处理。

  一、TestString是一个纯文本的字符串

  • 能够对pattern反向引用$N(N=0~9),紧跟在RewriteCond后面的RewriteRule正则表达式中第N个括号中的内容
  • 反向引用%N(N=0~9),表示RewriteCond中CondPattern中第N对括号中的内容
  • 服务器变量%{VARNAME}

  二、CondPattern是条件pattern,一个应用于当前实例TestString的正则表达式。即TestString与条件pattern条件进行匹配。若是匹配则RewriteCond的值为Rrue,反之为False

可使用如下特殊变量(可以使用'!'实现反转):

'>CondPattern’ (大于) 将condPattern看成一个普通字符串,将它和TestString进行比较,当TestString 的字符大于CondPattern为真。

‘=CondPattern’ (等于) 将condPattern看成一个普通字符串,将它和TestString进行比较,当TestString 与CondPattern彻底相同时为真.若是CondPattern只是 “” (两个引号紧挨在一块儿) 此时需TestString 为空字符串方为真。

‘-d’ (是否为目录) 将testString看成一个目录名,检查它是否存在以及是不是一个目录。

‘-f’ (是不是regular file) 将testString看成一个文件名,检查它是否存在以及是不是一个regular文件。

‘-s’ (是否为长度不为0的regular文件) 将testString看成一个文件名,检查它是否存在以及是不是一个长度大于0的regular文件。

‘-l’ (是否为symbolic link) 将testString看成一个文件名,检查它是否存在以及是不是一个 symbolic link。

‘-F’ (经过subrequest来检查某文件是否可访问) 检查TestString是不是一个合法的文件,并且经过服务器范围内的当前设置的访问控制进行访问。这个检查是经过一个内部subrequest完成的, 所以须要当心使用这个功能以下降服务器的性能。

‘-U’ (经过subrequest来检查某个URL是否存在) 检查TestString是不是一个合法的URL,并且经过服务器范围内的当前设置的访问控制进行访问。这个检查是经过一个内部subrequest完成的, 所以须要当心使用这个功能以下降服务器的性能。

   三、[flags]是第三个参数,多个标志之间用逗号隔开

’nocase|NC’ (不区分大小写)   在扩展后的TestString和CondPattern中,比较时不区分文本的大小写。注意,这个标志对文件系统和subrequest检查没有影响.

’ornext|OR’ (创建与下一个条件的或的关系)   默认的状况下,二个条件之间是AND的关系,用这个标志将关系改成OR。

 

  4)、Rewrite时服务器变量(仅列出少数)

HTTP headers:HTTP_USER_AGENT,  HTTP_REFERER,  HTTP_COOKIE,  HTTP_HOST,  HTTP_ACCEPT

connection & request:REMOTE_ADDR,  QUERY_STRING

server internals::DOCUMENT_ROOT,  SERVER_PORT,  SERVER_PROTOCOL

system stuff: TIME_YEAR,  TIME_MON,  TIME_DAY

 

 

  5)、简单正则表达式规则

. 匹配任何单字符

[chars] 匹配字符串:chars

[^chars] 不匹配字符串:chars

text1|text2 可选择的字符串:text1或text2

? 匹配0到1个字符

* 匹配0到多个字符

+ 匹配1到多个字符

^ 字符串开始标志

$ 字符串结束标志

\n 转义符标志

 【注意】:一代Apache要求URL有斜杠而二代Apache却不容许,所以使用 ^/?

 

 

四、例子解析

例1(简单例子):

(在.htaccess里进行规制重写)

RewriteEngine ON 
RewriteRule  ^user/(w+)/?$user.php?id=$1

^:输入的开头  以user/开头请求的地址

(w+):提取全部的字母,传给$1

/?:可选斜杠

$:结束符

替换为:user.php?id=*

注意:有些apache(具体哪一个版本忘啦)不兼容简写模式 w+ => [a-zA-Z_-]

 例2(禁止IE和Opera浏览器访问):

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} ^MSIE [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^Opera [NC]
RewriteRule ^.* - [F,L]       #'-'表示不替换URL

例3(不合法路径返回首页):

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

例4(防盗链):

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+.)?mysite.com/ [NC]       #判断请求的是不是本身的域名
RewriteCond %{HTTP_REFERER} !^$                     #{HTTP_REFERER}不为空
RewriteRule .*.(jpe?g|gif|bmp|png)$ /images/nohotlink.jpg [L]      #返回警告图片

例5(改变访问URL目录名):

即隐藏真实的目录名字

RewriteEngine On
RewriteRule ^/?old_dir/([a-z\.]+)$  new_dir/$1 [R=301,L]
#new_dir为真正目录

例6(建立无文件后缀连接):

RewriteEngine On
RewriteCond %{REQUEST_FILENAME}.php -f #判断该后缀文件是否存在
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.html -f #判断该后缀文件是否存在
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.html [L]

例7(限制只能显示图片):

RewriteEngine on
RewriteCond %{REQUEST_FILENAME}  !^.*\.(gif|jpg|jpeg|png|swf)$
RewriteRule .*$ - [F,L]

例8(文件不存在重定向404):

RewriteEngine on
RewriteCond  %{REQUEST_FILENAME}  !f
RewriteCond  %{REQUEST_FILENAME}  !d
RewriteRule .? /404.php [L]

 

例9 (入口文件重定向)URL重写,但不反应到浏览器上

普通的重写,会将重写后的URL反应到浏览器上,使用代理重写能够避免这种状况

此例子为本人实际项目中的案例。

当时的需求是这样的。

当时的php项目使用的fuelphp框架,几乎全部的URL请求(普通的资源请求除外,如css/js/图片等等)都通过入口文件index.php处理。由于有的请求须要basic认证,有的不须要,因此将index.php复制了一份为index2.php,即有两个入口文件。其中index.php须要basic认证,而index2.php不须要basic认证。index.php是默认入口,即URL中省略index.php时,默认会由index.php处理。

由index.php处理的URL: http://localhost/aa/bb (至关于http://localhost/index.php/aa/bb)

由index2.php处理的URL:http://localhost/index2.php/cc/dd

当时的要求把URL中的index2.php去掉,并且还不须要basic认证,即不能由index.php做为入口文件。所用用到了apache的重写功能。将去掉index2.php的URL请求重写回index2.php。可是普通的重写后,浏览器的URL中又会带有index2.php,因此只能用代理(【P】)的方法,使URL重写后不反应到浏览器上。

 

将不须要重写的URL做为条件列出,条件意外都重写

RewriteEngine on
RewriteCond %{REQUEST_URI} !^/file/.*    #普通的资源请求,不通过入口文件处理,不须要重写。 http://localhost/file/test.txt

RewriteCond %{REQUEST_URI} !^/sync/.*   #普通的资源请求,不通过入口文件处理,不须要重写。 http://localhost/sync/test.txt
RewriteCond %{REQUEST_URI} !^/assets/.*   #普通的资源请求,不通过入口文件处理,不须要重写。 http://localhost/assets/css/a.css
RewriteCond %{REQUEST_URI} !^/v[1-3]/.*  #API请求,须要basic认证,默认由index.php入口文件处理。不须要重写。 http://localhost/v1/search/search(至关于http://localhost/index.php/v1/search/search)

RewriteCond %{REQUEST_URI} !^/index.php/.*  #指定了入口文件的不须要重写   http://localhost/index.php/test1
RewriteCond %{REQUEST_URI} !^/index2.php/.*  #指定了入口文件的不须要重写  http://localhost/index2.php/test2
RewriteRule (.*) %{REQUEST_SCHEME}://%{SERVER_NAME}/index2.php/$1 [p]          #`其余省略入口文件的URL都要重写到index2.php # [P] 是使用代理的方式重写URL,这样重写后不会反应到浏览器上

注意,要想使用代理重写,须要加载相应的模块,还须要重写的字符串为完整的URL,从http://开始。  如上面的%{REQUEST_SCHEME}://%{SERVER_NAME}/index2.php/$1

LoadModule proxy_module         modules/mod_proxy.so
LoadModule proxy_http_module  modules/mod_proxy_http.so

另外,使用代理重写URL后,因为fuelphp框架的缘由,css等请求的主机名会变成重写后的主机名。为了不没必要要的麻烦,服务器的虚拟主机设置(/ctc/hosts)要与本地保持一致

相关文章
相关标签/搜索