Apache Rewrite 详解

Apache Rewrite 详解一 入门

通常LAMPPHP开发的黄金组合的确很好很强大不过现在流行URL要漂亮要符合SEO的爱好那么ApacheRewrite功能就比较引人瞩目了找了点时间把 Apache 的文件的 rewrite 部分细细看了一下果然能强大也很恶心强大的是你想要什么样的URL就可以写什么样的URL, 恶心的是里面的正则和规则很让人吐槽呵呵废话不说了. apache rewrite 的傻瓜实例讲解有时间的话陆续写在我的Blog估计得写上好几篇了有问题的和欢迎交流.

开始吧首先来个最简单的现在的 Zend Framework 是比较时髦了在网上看很多刚接触PHP网络编程的新人运行DEMO总有点小问题有部分是这由于服务器的rewrite模块这里的毛病一般搭建开发服务器的时候 WINDOW环境下要在apache 的 httpd.conf 文件里load mod_rewrite模块也就是把 rewrite模块前的"#" 去掉. Linux 下编译 apache 的时候记得加上带 rewrite 模块剩下的就没啥了phpinfo()里应该可以看到apacheload的模块列表里又 rewrite 名字我们先看看最简单的ZF 推荐的 .htaccess 文件里的内容.

RewriteEngine on

RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

就这两行然后就完成了URL重写功能了至于参数那些. ZF框架自己搞定了当然也可以交给apache处理不过这样入门难度就高了估计会被人骂的. :) 关于 ZF 的路由功能可以参考一下 ZF 的官方文档.

大概说一下上面的意思.

首先服务器是需要支持网站使用 .htaccess 文件模式这个需要服务器或者虚拟主机的配置段里给你配置 AllowOverride, 通常设置成 All 允许所有指令在 .htaccess 生效再看第一行:

RewriteEngine on 这行告诉apache服务器这个目录要使用URL重写功能了.

RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php 这行是具体的重写规则以上是如果有URL来访问该目录里的文件如果URL不是以 .js, .ico, .gif, .jpg, .png, .css 这几种结尾的话那么全部调用 目录下的 index.php 文件这个说起来比较费劲搞个具体的例子比如我们又一个网站域名为: www.test.com 该站支持 .htaccess 功能我们把上面两行保存为 .htaccess 放到网站目录下如果WINDOW下不允许保存这样的文件名的话没关系随便保存为 x.htaccess, 然后在DOS下 rename x.htaccess .htaccess 就行了.

www.test.com 网站根目录下放3个文件一个是 .htaccess, 一个是 logo.png, 一个是 index.php

测试一在浏览器地址栏里输入: http://www.test.com/ 很正常页面应该默认显示 index.php 文件的内容.

测试二在浏览器地址栏里输入: http://www.test.com/logo.png 也很正常网页里应该看到了这个png图片了.

测试三在浏览器地址栏里输入: http://www.test.com/test.php 这样一般来说如果没开重写功能的话通常你会看到404错误这说明你服务器APACHErewrite功能没生效不然你看到的是和 测试一一样的内容因为请求 test.php 被定向到 index.php. 其实是和访问http://www.test.com/index.php 一个效果这就是apache最简单的rewrite功能了.

OK, 另外再说名一下 .htaccess 文件里的一些小事情如果你要给指令添加注释防止复杂的重写规则时间常了要修改的话还要费劲去看,或者协作开发让别人能很容易看懂这样只要在每行的第一个字符写成"#" 就行了通常的指令的第一个字符是一个大写英文字母后面的是按照驼峰命名法写出比如开启重写指令: RewriteEngine, 指令值一般是小写的字符串像上面的 RewriteEngine on

再看一下完整的简单的.htaccess文件代码:

#该目录下使用Apache Rewrite 功能. RewriteEngine on  #所有的访问请求除了是以 .js, .ico, .gif, .jpg, .png, .css 结尾都定向到index.php脚本 RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php 上面的重写规则指令用到了正则表达式这方面不太了解的话想去补充一下不然后面的部分会看起来比较费劲.

关于 RewriteRule 这个是比较能让人花点时间玩的东西了下篇问详细介绍它的用法和参数.

/--------------------------------------------------------------------------------------------------------------------------------------------------------

Apache Rewrite 详解二 参数标志[Flag]

上一篇聊了一下最简单的重写模式在进入比较好玩的重写模式之前先给说名一下重写规则后面的那些中括号里的大写字符是什么意思不然会让你看后面的代码晕头转向的关于这些参数的说明在 apache.org 的官方文档里有说明可惜没有中文的我大概的翻译了一下表面意思建议去看原E文文档. E文实在不好的先凑合着看看官方关于 Rewrite Flag 文档地址在: http://httpd.apache.org/docs/2.2/rewrite/rewrite_flags.html

 

重写规则的一般模式为下面的语法.

RewriteRule pattern target [Flag1,Flag2,Flag3]

RewriteRule 规则可以在后面添加标志(Flag), 可以又多个 flag, 多个 flag 用逗号"," 连接.

 

先说明一下一个比较特别的 target : "-", 如果目标是 "-" 的话那么被请求的URL不会被修改掉.

 

下面详细简介一下各个 flag 代表的意思.

 

C|chain

C|chain 意思字符 'C' 或者 字符串 'chain' 表示出了该行重写规则外还要有其他的重写规则相当于通常程序语言的 与符号 '&' , 如果第一条规则条匹配的话进行下一项条件匹配如果第一条或者中间一条匹配不成功在其后的都会被跳过.

 

CO|cookie

CO|cookie 意思字符 'CO' 或者 字符串 'cookie' 表示当某些特殊的规则被匹配到的时候允许设置一个COOKIE, 设置参数包含3个必须字段和2个可选字段.

三个必须的字段是设定COOKIE的名字还有这个COOKIE的所属域名另外两个可选的字段是COOKIE的生存时间和路径.默认的COOKIE生存时间是浏览器的会话时间默认的路径是 '/', 针对整个网站.

实际的使用例子想下面这样

RewriteEngine On

# RewriteRule 匹配模式 - [CO=COOKIE名称:COOKIE:COOKIE域名:生存时间:路径各个参数用冒号:连接

RewriteRule ^/index.html - [CO=mycookie:myCookieValue:.test.com:1440:/]

#RewriteRule ^/index.html - [CO=mycookie:myCookieValue:.test.com] 或者省略后面的参数.

上面的规则的意思是在请求 index.html 文件的时候设置一个COOKIE. COOKIE名是 mycookie, 值是:myCookieValue, 生效的域名是 .test.com, 生效时间是分钟计算的也就是生存时间是1=24小时=1440分钟.

 

E|env

E|env 意思字符 'E' 或者 字符串 'env' 表示你可以设置一个环境变量注意一下变量在这个规则运行后生效.

看一个简单的例子就是apache在记录日志的时候不记录图片的读取记录那么下面的规则就有用了.

RewriteRule \.(png|gif|jpg) - [E=image:1]

CustomLog logs/access_log combined env=!image

 

F|forbidden

F|forbidden 意思字符 'F' 或者 字符串 'forbidden' 表示禁止访问. Apache服务器会返回403禁止访问状态码给客户端.

下面的规则表示获取或者下载 exe程序文件是被显示禁止访问.

RewriteRule \.exe - [F]

 

G|gone

G|gone 意思字符 'G' 或者 字符串 'gone' 表示服务器响应状态码为:410 通常使用该标志的时候 target 目标值设置成 "-" 被请求的资源是有效的.

下面的例子表示旧的资源是有效的并且不在乎大小写.

RewriteRule oldproduct - [G,NC]

 

H|handler

H|handler 意思字符 'H' 或者 字符串 'handler' 表示强制使用某类型处理程序处理被请求的资源比如请求一些不带后缀的文件的时候下面的列子表示当请求的URL里没有带'.'的时候强制使用PHP来处理这类的请求.

RewriteRule !\. - [H=application/x-httpd-php]

 

L|last

L|last 意思字符 'L' 或者 字符串 'last' 表示当前规则是最后一条规则,停止分析以后规则的重写。该标志的使用频率非常高.

RewriteCond %{REQUEST_URI} !index\.php

RewriteRule ^(.*) index.php?req=$1 [L]

一定要注意的地方使用[L]标志的时候一定要注意你的匹配条件不会非常容易让你的重写规则陷入死循环比如你要定义页面所有页面请求都重写到一个 index.php 文件那么一定要注意在匹配条件时确定当请求的脚本不是index.php时才执行重写规则不然很明显当前页面请求的是 index.php, 当然 这个请求被重写到 index.php 然后index.php又被重写到index.php.. 这样反复执行页面会报错错误日志会记录报告你超出最大的重定向次数.

 

N|next

N|next 意思字符 'N' 或者 字符串 'next' 表示重新回到规则顶部重复执行一般在极端情况下用这个标志相当于一个while循环知道匹配失败时返回下面的例子表示把请求地址中的所有A字符替换成B字符.

RewriteRule (.*)A(.*) $1B$2 [N]

 

NC|nocase

NC|nocase 意思字符 'NC' 或者 字符串 'nocase' 表示请求的规则部分不区分大小写类似正则式里的/xxx/i 模式.

RewriteRule (.*\.(jpg|gif|png))$ http://images.test.com$1 [P,NC]

 

NE|noescape

NE|noescape 意思字符 'NE' 或者 字符串 'noescape' 表示不对URL中的特殊字符进行 hexcode 转码.看下面的例子:

RewriteRule ^/share/(.+) /goShare.html#$1 [NE,R]

上面的例子表示所有请求 /share/xxx.xx的请求都会被定向到/goShare.html文件上并且后面的部分作为一个#后面的值如果不加NE标志的话, #将被转义成 %23 这样就造成 404 错误了.

 

NS|nosubreq

NS|nosubreq 意思字符 'NS' 或者 字符串 'nosubreq' 表示只用于不是内部子请求.比如,在mod_include试图搜索可能的目录默认文件(index.xxx)时, Apache会内部地产生子请求。对子请求,它不一定有用的,而且如果整个规则集都起作用,它甚至可能会引发错误。所以,可以用这个标记来排除某些规则。根据你的需要遵循以下原则如果你使用了有CGI脚本的URL前缀,以强制它们由CGI脚本处理,而对子请求处理的出错率(或者开销)很高,在这种情况下,可以使用这个标记。

 

P|proxy

P|proxy 意思字符 'P' 或者 字符串 'proxy' 标志需要模块 mod_proxy 支持类似一个分发器网关的作用.比如网站的所有图片想用单独的一台服务器来运行那么先前的代码里的图片请求的时候直接定向到图片服务器去.

RewriteRule (.*)\.(jpg|gif|png) http://images.example.com$1.$2 [P]

使用[P]标志意味着使用了[L]标志因为使用该标志后马上就重定向到新地址了后面的重写规则会被忽略掉.

 

PT|passthrough

PT|passthrough 意思字符 'PT' 或者 字符串 'passthrough' 表示替换URL请问部分的地址.看例子

Alias /icons /usr/local/apache/icons

RewriteRule /pics/(.+)\.jpg /icons/$1.gif [PT]

当请求/pics/下的图片文件时实际是返回的是 /icons/目录下的同名文件需要注意的是一定要设置 [PT] 标志否则Alias设置无效.

 

QSA|qsappend

QSA|qsappend 意思字符 'QSA' 或者 字符串 'qsappend' 不怎么好表示看例子:

RewriteRule /pages/(.+) /page.php?page=$1 [QSA]

如果又标志: [QSA] 那么重写后的URL: /page.php?page=123&one=two

如果没有[QSA]标志那么结果是: /page.php?page=123

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

 

R|redirect

R|redirect 意思字符 'R' 或者 字符串 'redirect' 表示进行重定向状态码在300-399里随机出默认是 302 重定向.通常和标志L一起使用使用模式: [R[=302]]

 

S|skip

T|type 意思字符 'S' 或者 字符串 'skip' 表示跳过执行下面的几个重写规则又点类似goto. 看下面的例子如果URL请求的文件不存在的话就跳过下面的两行重写规则.

请求的文件是否存在

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

不存在的情况

RewriteRule .? - [S=2]

RewriteRule (.*\.gif) images.php?$1

RewriteRule (.*\.html) docs.php?$1

 

T|type

T|type 意思字符 'T' 或者 字符串 'type' 表示为apache设置特定请求的响应类型也就是常说的 MIME type,比如一个perl脚本希望给客户端显示文本源码那么可以这样做:

RewriteRule \.pl$ - [T=text/plain]

或者你的服务器上的文件没有设置扩展名那么可以通知重写添加该文件的类型方便客户端显示.

RewriteRule IMG - [T=image/jpg]

 

以上就是Apache 官方文档提到的全部标志值及其相关的意思了接下来我们将介绍他们用到具体的实际例子中去上面代码的例子看不懂没关系接下来我会很详细的解释它的. :)  这篇就先到这里吧.

----------------------------------------------------------------------------------------------------------------------------------------------------------Apache Rewrite 详解三 服务器变量

上一篇日志大概了解了重写规则的标志量的意思这篇先把Apache 能提供给rewrite模块的服务器变量信息了解一下不然会在以后的重写规则中对变量的大概内容都不了解理解起来就比较费劲了.

需要注意的一点是在 .htaccess 文件中使用服务器参数是的写法是: %{参数名}, 比如HOST名称: %{HTTP_HOST}

Apache提供给rewirte模块的环境变量大概分成5个类型下面一一说明.

 

第一部分: HTTP headers 部分参数

参数名称: HTTP_USER_AGENT

样例参考值: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8

说明相当于PHP中的服务器参数: $_SERVER["HTTP_USER_AGENT"]

参数名称: HTTP_REFERER

样例参考值: http://www.test.cn/test.php

说明相当于PHP中的服务器参数: _SERVER["HTTP_REFERER"]

参数名称: HTTP_COOKIE

样例参考值: ZDEDebuggerPresent=php,phtml,php3

说明相当于PHP中的服务器参数: $_SERVER["HTTP_COOKIE"]

参数名称: HTTP_FORWARDED

样例参考值如果使用代理服务器的话会是代理服务器的IP地址本地不容易搭环境测试出值来.

说明相当于PHP中的服务器参数: $_SERVER["HTTP_FORWARDED"]

参数名称: HTTP_HOST

样例参考值: www.test.com

说明相当于PHP中的服务器参数: $_SERVER["HTTP_HOST"]

参数名称: HTTP_PROXY_CONNECTION

样例参考值网络连接代理方面的信息HTTP_FORWARDED参数一样本地不容易搭环境测试出值来.

说明: PHP中貌似未提供这样的服务器信息值如果又的话可能等值于: $_SERVER["HTTP_PROXY_CONNECTION"]

参数名称: HTTP_ACCEPT

样例参考值: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

说明相当于PHP中的服务器参数: $_SERVER["HTTP_ACCEPT"]

 

第二部分: server internals 部分参数

参数名称: DOCUMENT_ROOT

样例参考值: C:/webRoot/t

说明相当于PHP中的服务器参数: $_SERVER["DOCUMENT_ROOT"]

参数名称: SERVER_ADMIN

样例参考值[email protected]

说明相当于PHP中的服务器参数: $_SERVER["SERVER_ADMIN"]

参数名称: SERVER_NAME

样例参考值: www.test.com

说明相当于PHP中的服务器参数: $_SERVER["SERVER_NAME"]

参数名称: SERVER_ADDR

样例参考值: 127.0.0.1

说明相当于PHP中的服务器参数: $_SERVER["SERVER_ADDR"]

参数名称: SERVER_PORT

样例参考值: 80

说明相当于PHP中的服务器参数: $_SERVER["SERVER_PORT"]

参数名称: SERVER_PROTOCOL

样例参考值: HTTP/1.1

说明相当于PHP中的服务器参数: $_SERVER["SERVER_PROTOCOL"]

参数名称: SERVER_SOFTWARE

样例参考值: Apache/2.2.11 (Win32) PHP/5.2.9-1

说明相当于PHP中的服务器参数: $_SERVER["SERVER_SOFTWARE"]

 

第三部分: connection & request 部分参数

参数名称: REMOTE_ADDR

样例参考值: 127.0.0.1 正在浏览当前页面用户的 IP 地址。

说明相当于PHP中的服务器参数: $_SERVER["REMOTE_ADDR"]

参数名称: REMOTE_HOST

样例参考值: 127.0.0.1 正在浏览当前页面用户的主机名。反向域名解析基于该用户的 REMOTE_ADDR

说明相当于PHP中的服务器参数: $_SERVER["REMOTE_HOST"]

参数名称: REMOTE_PORT

样例参考值: 2574 (变化的值)用户连接到服务器时所使用的端口

说明相当于PHP中的服务器参数: $_SERVER["REMOTE_PORT"]

参数名称: REMOTE_USER

样例参考值

说明: PHP 好像未提供相关的$_SERVER.

参数名称: REMOTE_IDENT

样例参考值

说明: PHP 好像未提供相关的$_SERVER.

参数名称: REQUEST_METHOD

样例参考值: GET

说明相当于PHP中的服务器参数: $_SERVER["REQUEST_METHOD"]

参数名称: SCRIPT_FILENAME

样例参考值: C:/webRoot/t/share77.html

说明相当于PHP中的服务器参数: $_SERVER["SCRIPT_FILENAME"]

参数名称: PATH_INFO

样例参考值

说明相当于PHP中的服务器参数: $_REQUEST["PATH_INFO"]

参数名称: QUERY_STRING

样例参考值: a=b&c=d&e=f

说明相当于PHP中的服务器参数: $_SERVER["QUERY_STRING"]

参数名称: AUTH_TYPE

样例参考值空 当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个是认证的类型

说明相当于PHP中的服务器参数: $_SERVER["AUTH_TYPE"]

 

第四部分: date and time 部分参数

参数名称: TIME_YEAR

样例参考值: 2009

说明服务器获取当前的年份值

参数名称: TIME_MON

样例参考值: 04

说明服务器获取当前的月份值

参数名称: TIME_DAY

样例参考值: 22

说明服务器获取当前的日值

参数名称: TIME_HOUR

样例参考值: 16

说明服务器获取当前时间的小时

参数名称: TIME_MIN

样例参考值: 26

说明服务器获取当前时间的分钟

参数名称: TIME_SEC

样例参考值: 34

说明服务器获取当前时间的秒

参数名称: TIME_WDAY

样例参考值: 3

说明服务器获取当天是星期几从星期日-星期六数字从 0-6

参数名称: TIME

样例参考值: 20090422162634

说明服务器获取当前的时间格式为年月日时分秒

 

第四部分: specials 部分参数

参数名称: API_VERSION

样例参考值: 20051115:21

说明: apache 的 API 版本信息.

参数名称: THE_REQUEST

样例参考值: GET /share77.html HTTP/1.1

说明浏览器发给服务器的请求值不包括其他的头信息.

参数名称: REQUEST_URI

样例参考值: /share77.html

说明浏览器请求的资源信息.

参数名称: REQUEST_FILENAME

样例参考值: C:/webRoot/t/share77.html

说明被请求的资源的在磁盘的物理地址.

参数名称: IS_SUBREQ

样例参考值: false

说明如果是 sub-request 则显示为 true, 否则为 false.

参数名称: HTTPS

样例参考值: off

说明如果连接使用 SSL/TLS 模式则值为on , 否则值为off, 这个参数比较安全即使未载入 mod_ssl 模块时.

OK, 以上就是Apache手册里提到的全部的服务器变量信息了这篇先到这里了. :)

==================

Apache Rewrite 详解四 杂项 

前篇介绍了Apache Rewrite 的服务器变量信息在进入重写实战之前有些小细节了解一下是很又必要的.

首先一点如果在重写规则的正则里要使用特殊字符的时候需要在该特殊字符前带一个转义字符反斜杠比如匹配一个百分号:%, 那么正确的写法就该是: \%, 其他的特殊字符均按此写法.

另外还有官方手册里提到的四个比较重要的服务器变量. SCRIPT_NAME, SCRIPT_FILENAME, SCRIPT_URL, SCRIPT_URI

其中 SCRIPT_NAME 和 SCRIPT_FILENAME apache会跟踪的两个标准CGI/SSI变量他们包含的是物理系统视图.

官方文档的示例值:

SCRIPT_NAME=/sw/lib/w3s/tree/global/u/rse/.www/index.html

SCRIPT_FILENAME=/u/rse/.www/index.html

另外还会跟踪两个非标准的变量 SCRIPT_URL 和 SCRIPT_URI. 他们包含的是逻辑网络视图.

官方文档的示例值:

SCRIPT_URL=/u/rse/

SCRIPT_URI=http://en1.engelschall.com/u/rse/

实际上按照上面的说法看起来

SCRIPT_NAME 的值是资源请求文件在服务器的实际地址.

SCRIPT_FILENAME 资源相对于站点根目录的实际地址.

SCRIPT_URL 则是URL的相对路径.

SCRIPT_URI 则是网络请求的绝度路径.

不过在实际测试中并未发现是上面的情况服务器配置环境为WINXP+APACHE2.2.11+PHP-5.2.9, module模式和 Linux+Apache2.2.6+PHP-5.2.5, module 模式四个变量中 SCRIPT_FILENAME 在没有 Alians 指令下未脚本在服务器端的实际地址. SCRIPT_NAME为请求的脚本相对应网站根目录的地址例如:/test.php 另外两个非标准变量为空如果在 重写规则中使用上面的四个变量需要注意一下.

另外正则部分又个"!"表示否的意思其他的正则和perl的正则类似这方面没信息的先看看正则方面的资料本系列完结后分享一个重写很系统的图表到时候作为一个查询工具非常方便.

=======================

Apache Rewrite 详解五 RewriteBase

现在我们了解一下 Apache Rewrite 的重写规则的具体指令吧.

重写规则具体有 RewriteBase, RewriteCond, RewriteEngine, RewriteLock, RewriteLog, RewriteLogLevel, RewriteMap, RewriteOptions, RewriteRule 九个指令通常最常用的是 RewriteEngine, RewriteBase, RewriteCond, RewriteRule 四个指令这个我们要重点讲解的如果这四个指令运用的比较熟练的话不是特别的网站基本上你想出什么样的URL 都可以满足你的需要了其他的指令就不在讲解了如果对前面说的4个指令比较熟悉的话剩下的去看看 apache 的手册相信掌握这些不会费你很多脑筋.

RewriteEngine 这个指令就不用说了就是是否使用 Rewrite 模式的开关使用就设置成 on, 否则设置成 off 作用域在: server config, virtual host, directory, .htaccess

我们这篇日志专门讲解: RewriteBase

RewriteBase 的作用域为: directory, .htaccess

通常默认的虚拟主机的网站在使用.htaccess 进行重写规则时不需要执行设置该指令因为 RewriteBase 默认值是该 .htaccess 文件所在的目录地址.

但是如果使用目录别名的话就需要设置这个指令了先看官方手册的例子假设一个网站目录使用了别名操作: Alias /xyz /abc/def 那么当客户端访问/xyz/xxx.html 文件时是相当于访问 /abc/def/xxx.html然后看看在使用了别名的情况下重写效果当然这个 .htaccess 文件在 /abc/def/.htaccess 位置内容如下:

RewriteEngine On

RewriteBase /xyz

RewriteRule ^oldstuff\.html$ newstuff.html

假设访问服务器的: /xyz/oldstuff.html (比如: http://www.test.com/xyz/oldstuff.html 这样).

服务器处理流程大概是下面的样子.

第一步alias别名还原成真实的路径:

/xyz/oldstuff.html -> /abc/def/oldstuff.html  (per-server Alias)

第二步, rewrite前会去掉前缀(也就是.htaccess文件所在的目录部分这里是/abc/def/), 然后执行重写规则处理完之后再把前缀添加上去:

/abc/def/oldstuff.html -> /abc/def/newstuff.html  (per-dir    RewriteRule)

第三步由于设定了RewriteBase,所以路径最后还是被还原回去:

/abc/def/newstuff.html -> /xyz/newstuff.html      (per-dir    RewriteBase)

第四步重写规则完成别名再次使用最后得到的结果:

/xyz/newstuff.html     -> /abc/def/newstuff.html  (per-server Alias)

实际上相当于请求: /abc/def/newstuff.html, 关于 alias 的用法和意思请另行参考 apache 手册.

这里要注意的是即使RewriteBase /xyz 这行被注释掉服务器还是会执行上面的 第一步第二步后面的不会被执行服务器执行完第二步以后就发出一个内部重定向按照上面的例子也就是 GET /abc/def/newstuff.html, 由于GET 模式获取到第一个是/开头的相当于请求DocumentRoot目录下的/abc/def/newstuff.html, 换成客户端请求的模式也就是 http://www.test.com/xyz/oldstuff.html 变成了 http://www.test.com/abc/def/newstuff.html 如果 /xyz 只是目录的别名, DocumentRoot 目录下根本没有实际的物理目录 abc/def 这样最终会导致一个 404 报错.

另外有一点就是在进行重写规则的时候. apache 会去掉目录前缀注意这个时候剩下的文件名或者相对目录第一个字符不是 开头的而直接是文件名或者目录这样的模式关于访问 http://www.test.com 和 访问 http://www.test.com/ 又什么不同(最后加斜杠和不加斜杠). 服务器已经强制进行过了一次重定向(外部定向)如果服务器未处理这类的事情的话就需要手动处理不然错误日志漫天飞那会是很痛苦的事情呢!

OK, 说完了收工先下篇说一下 RewriteCond.

Apache Rewrite 详解六 RewriteCond

RewriteCond 重写规则执行条件

语法: RewriteCond TestString CondPattern

生效域: server config, virtual host, directory, .htaccess

特别的上面的 TestString, 可提供反向引用引用模式为: %N 其中N(0 <= N <=9), 引用当前若干RewriteCond条件中最后符合的条件中的分组成分也就是括号里的内容.不过用到的不多反向应用多在RewriteRule里常用.

RewriteCond 语法中的 TestStrng 为要被检查的内容, CondPattern 是进行匹配的规则它是一个兼容Perl风格的正则表达式和一些其他的特有字符属性这里介绍一下.

第一个: ! (感叹号表示否的意思比如一个条件判断访问此页面的上一页URL是否包含 sex 字符的话可以用这样: RewriteCond %{HTTP_REFERER} !(sex)

第二个: < 就是小于的意思, TestString < CondPattern.

第三个: > 就是大于于的意思, TestString < CondPattern.

第四个: = 相等的意思. <, >, = 三个和通常程序语言使用的 <, >, = 功能类似.

第五个: -d 是否是一个目录判断TestString是否不是一个目录可以这样: !-d

第六个: -f 是否是一个文件判断TestString是否不是一个文件可以这样: !-f

第七个: -s 是否是一个正常的有大小的文件判断TestString是否不是一个正常的有大小的文件可以这样: !-s

第八个: -l 是否是一个快捷方式文件判断TestString是否不是一个快捷方式文件可以这样: !-l

第九个: -x 是否是一个文件并且又执行权限判断TestString是否不是一个文件并且又执行权限可以这样: !-x

第十个: -F 检查TestString是否是一个合法的文件,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的因此需要小心使用这个功能以降低服务器的性能。

第十一个: -U 检查TestString是否是一个合法的URL,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的因此需要小心使用这个功能以降低服务器的性能.

另外: RewriteCond 指令后面可带 Flag, 现在只要2个可用一个是 NC|nocase, 不区分大小写的意思一个是 OR|ornext 表示连接下一个条件的意思.

RewriteCond 实际需要使用情况比如要判断一个条件成真的时候才执行相关的重写操作紧接着它下面的 RewriteRule 总是在RewriteCond 条件判断为真的时候才被执行.

看下面的一个例子:

#开启服务器重写模式

RewriteEngine on

#来自 www.test.cn 的连接访问本站时都只能访问 test.php 这页.

RewriteCond %{HTTP_REFERER} (www.test.cn)

RewriteRule (.*)$ test.php

#来自 www.test.com 的连接访问本站时都只能访问 newTest.php 这页.

RewriteCond %{HTTP_REFERER} (www.test.com)

RewriteRule (.*)$ newTest.php

OK, RewriteCond 就介绍到这里了其实很简单就想程序里的 if() 这样的效果下篇聊一下  RewriteRule

Apache Rewrite 详解六 RewriteRul

这两天回家了一趟又匆忙的赶回公司上班坐车那个累啊继续把 Apache 重写规则部分讲完.

前面的几篇关于重写的日志如果都看了的话这里就很容易了值得注意的地方是网站使用URL重写的话需要服务器配置 RewriteEngine On 和 Options FollowSymLinks, 不然重写规则不生效.

重写规则语法很简单: RewriteRule Pattern Substitution [Flag] 作用域为: server config, virtual host, directory, .htaccess

指令说明匹配部分(Pattern) 是正则匹配URL的正则表达式(注意特殊字符需要转义处理), 可以在替换部分(Substitution)使用反向引用匹配部分的内容引用模式为: $N (N1-9的整数).

URL重写的匹配部分中服务器会把请求的URL的一部分删除掉再传递给Pattern部分进行匹配重写结束后再添加上去所有平常我们看到的匹配规则总是不带网址前面的那些域名的什么东西的也不带什么目录什么的这些 apache已经给删掉了处理完后再加到前面但是有个例外就是如果 Substitution 部分是带 http:// 开头的话那就直接重定向了服务器不会把先前删除的再给加上了不然就出错了.

给出个形象的流程图见下图:

官方的例子重写规则写在 httpd.conf 文件里请求地址为: http://www.test.com/somepath/pathinfo, 看下面几种结果.

Given Rule => Resulting Substitution

-------------------------------------------------------------------------------

^/somepath(.*) otherpath$1 => 不支持无效的重写语句

^/somepath(.*) otherpath$1 [R] => 不支持无效的重写语句

^/somepath(.*) otherpath$1 [P] => 不支持无效的重写语句

-------------------------------------------------------------------------------

^/somepath(.*) /otherpath$1 => /otherpath/pathinfo

^/somepath(.*) /otherpath$1 [R] =>  http://www.test.com/otherpath/pathinfo  外部重定向

^/somepath(.*) /otherpath$1 [P] =>  不支持很傻.

-------------------------------------------------------------------------------

^/somepath(.*) http://www.test.com/otherpath$1 => /otherpath/pathinfo

^/somepath(.*) http://www.test.com/otherpath$1 [R] => http://www.test.com/otherpath/pathinfo  外部重定向

^/somepath(.*) http://www.test.com/otherpath$1 [P] => 不支持很傻.

----------------------------------------------  ----------------------------------

^/somepath(.*) http://www.xxx.com/otherpath$1 => http://www.xxx.com/otherpath/pathinfo  外部重定向

^/somepath(.*) http://www.xxx.com/otherpath$1 [R] => http://www.xxx.com/otherpath/pathinfo  外部重定向 [R] 多余.

^/somepath(.*) http://www.xxx.com/otherpath$1 [P] => http://www.xxx.com/otherpath/pathinfo 内部网关重定向

同样的请求上面的地址如果在 .htaccess 文件里的写法注意和 httpd.conf 写法的区别.

比如 .htaccess 文件在目录一个虚拟主机的根目录下然后请求 http://www.test.com/localpath/pathinfo 看下面的几种结果.

Given Rule => Resulting Substitution

-------------------------------------------------------------------------------

^localpath(.*) otherpath$1=> /otherpath/pathinfo

^localpath(.*) otherpath$1  [R] =>  http://www.test.com/otherpath/pathinfo 外部重定向

^localpath(.*) otherpath$1  [P] => 不支持很傻.

-------------------------------------------------------------------------------

^localpath(.*) /otherpath$1 => /otherpath/pathinfo 注意 /otherpath$1 和 otherpath$1 的区别

^localpath(.*) /otherpath$1 [R] => http://www.test.com/otherpath/pathinfo 外部重定向

^localpath(.*) /otherpath$1 [P] => 不支持很傻.

-------------------------------------------------------------------------------

^localpath(.*) http://www.test.com/otherpath$1      /otherpath/pathinfo

^localpath(.*) http://www.test.com/otherpath$1 [R]  http://www.test.com/otherpath/pathinfo 外部重定向

^localpath(.*) http://thishost/otherpath$1 [P] => 不支持很傻.

-------------------------------------------------------------------------------

^localpath(.*) http://www.test.com/otherpath$1 => http://www.test.com/otherpath/pathinfo 外部重定向

^localpath(.*) http://www.xxx.com/otherpath$1 [R] => http://www.xxx.com/otherpath/pathinfo 外部重定向 [R] 可省略

^localpath(.*) http://www.xxx.com/otherpath$1 [P] => http://www.xxx.com/otherpath/pathinfo 内部网关重定向

细细的看上面的例子重写规则还是比较简单的下面放出一些常用的例子我们使用 .htaccess 来定义重写规则假设域名为: www.test.com

.htaccess 放在网站根目录下比如: /.htaccess

例子1: 所有请求都定向到 index.php 脚本注意要排除 index.php 本身比如就进入死循环了.

RewriteRule !^index\.php$ index.php [L]

例子2: 当请求不存在的资源时统一定义到根目录下的 404.html

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^.*$ /404.html [L]

例子3: 限制访问比如来自一些不友好的网站连接过来的请求不允许访问下例中如果 HTTP_REFERER 中包含 sex 字符则不允许访问.

RewriteCond %{HTTP_REFERER} sex

RewriteRule ^.*$ - [F]

例子4: 按照时间显示不同的页面比如访问 hello.html 页面时如果 在 8:00-19:00 的时候访问显示 hello.day.html 其他时间访问显示: hello.night.html

RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700

RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900

RewriteRule ^hello\.html$ hello.day.html

RewriteRule ^hello\.html$ hello.night.html

例子5: 伪静态化比如访问 /user20.html 则调用viewUser.php 显示用户ID20的用户资料

RewriteRule ^user([0-9]*)\.html$ viewUser.php?userid=$1

例子6: 喜欢用二级域名的比较实用了比如网站目录下有 user, upload 等几个目录可以通过 http://www.test.com/user 这样的模式访问但是如果想做成统一用二级域名模式访问: http://user.test.com , 但是不允许 http://www.test.com/user 这样访问那么就像下面这样来限制.

RewriteCond %{REQUEST_URI} ^/user

RewriteRule ^.*$ http://user.test.net" [L]

关于重写条件的设置可以任意由你自己来定义其他的例子就不多举了. URL可以由你任意摆布.

重写还又很多高级功能这个需要自己慢慢的研究了特别关于负载均衡反向代理等其他很多有意思的高级功能可以慢慢去玩了本篇就到此为止了.

Apache重写规则的常见应用(rewrite)

       一:目的

  本文旨在提供怎么用Apache重写规则来解决一些常见的URL重写方法的问题,通过常见的

  实例给用户一些使用重写规则的基本方法和线索。

  二:为什么需要用重写规则?

  一个网站,如果是长期需要放在internet上提供服务,必定会有不断地更新和维护,如临

  时转移到其他服务器进行维护,重新组织目录结构,变换URL甚至改动到新的域名等等,

  而为了让客户不会因此受到所有影响,最佳的方法就是使用Apache Rewrite Rule(重写

  规则)

  三重写规则的作用范围

  1) 能使用在Apache主设置文件httpd.conf

  2) 能使用在httpd.conf里定义的虚拟主机设置中

  3) 能使用在基本目录的跨越设置文件.htaccess

  四:重写规则的应用条件

  只有当用户的WEB请求最终被导向到某台WEB服务器的Apache后台,则这台WEB服务器接受

  进来的请求,根据设置文件该请求是主设置还是虚拟主机,再根据用户在浏览器中请求的

  URI来配对重写规则并且根据实际的请求路径配对.htaccess中的重写规则。最后把请求

  的内容传回给用户,该响应可能有两种:

  1) 对浏览器请求内容的外部重定向(Redirect)到另一个URL

  让浏览器再次以新的URI发出请求(R=301R=302,临时的或是永久的重定向)

  如:一个网站有正规的URL和别名URL,对别名URL进行重定向到正规URL,或网站改换

  成了新的域名

  则把旧的域名重定向到新的域名(Redirect)

  2) 也可能是由Apache内部子请求代理产生新的内容送回给客户[P,L]

  这是Apache内部根据重写后的URI内部通过代理模块请求内容并送回内容给客户,而客户

  端浏览器并

  不知道,浏览器中的URI不会被重写。但实际内容被Apache根据重写规则后的URI得到。

  如:在公司防火墙上运行的Apache启动这种代理重写规则,代理对内部网段上的WEB服务

  器的请求。

  五:重写规则怎样工作?

  我们假定在编译Apache时已把mod_rewrite编译成模块,确信你的httpd.conf中有

  LoadModule rewrite_module libexec/mod_rewrite.so

  并且在Addmodule中有

  Addmodule mod_rewrite.c

  则能使用重写规则。

  当外部请求来到ApacheApache调用重写规则中的定义来重写由用户浏览器指定请求的

  URI,最后被重写的URI如果是重定向,则送由浏览器作再一次请求;如果是代理则把重写

  后的URI交给代理模块请求最终的内容(Content),最后把内容送回给浏览器。

  六何时使用.htaccess中的重写规则定义?

  如果你对你的的网站内容所在的服务器没有管理员权限,或你的网站放在ISP的服务器

  上托管等等条件下,你无法改写主设置文件,然而你能对你的WEB站点内容所在的目录

  有写权限,则你能设置自己的.htaccess

  文件达到同样的目的。但你需要确定主设置文件中对你的网站所在的目录定义了下面的内

  容:

  Options Indexes FollowSymLinks

  AllowOverride all

  否则你的.htaccess不会工作。

  七应用举例

  假定Apache被编译安装在主机192.168.1.56/usr/local/apache/ 目录下面,我们编

  译进了重写和代理模块。

  1) 隐藏Apache下的某个目录,使得对该目录的所有请求都重定向到另一个文件。

  a> httpd.conf的实现方法

  我们放下面的部分到/usr/local/apache/conf/httpd.conf

  options Indexes followsymlinks

  allowoverride all

  rewriteengine on

  rewritebase /

  rewriterule ^(.*)$ index.html.en [R=301]

  注:rewriteengine on 为重写引擎开关,如果设为off,则所有重写规则定义将不被应

  用,该开关的另一好处就是如果为了临时拿掉重写规则,则改为off再重启动Apache

  可,不必将下面一条条的重写规则注释掉。

  rewritebase / 的作用是如果在下面的rewriterule定义中被重写后的部分(此处为文件

  名index.html.en)前面没有/,则是相对目录,相对于这个rewritebase后面的定义也就

  是/usr/local/apache/htdocs/index.html.en,否则,如果此处没有rewritebase /

  一项,则被重写成

  http://192.168.1.56/usr/local/apache/htdocs/manual/index.html.en ,显然是

  不正确的。

  不过这里我们也能不用rewritebase / , 而改为

  rewriteengine on

  rewriterule ^(.*)$ /index.html.en [R=301]

  或

  rewriteengine on

  rewriterule ^(.*)$ http://192.168.1.56/index.html.en [R=301]

  b> .htaccess的实现方法

  我们先放下面的部分到httpd.conf

  options Indexes followsymlinks

  allowoverride all

  然后放下面的部分到/usr/local/apache/htdocs/manual/.htaccess

  rewriteengine on

  rewritebase /

  rewriterule ^(.*)$ index.html.en [R=301]

  注:对文件.htaccess所作的所有改动不必重启动Apache.

  问:要是把这个manual目录重定向到用户jephe的自己的主目录呢?

  用下面的.htaccess方案。

  rewriteengine on

  rewritebase /~jephe/

  rewriterule ^(.*)$ $1 [R=301]

  则对manual目录下所有文件的请求被重定向到~jephe目录下相同文件的请求。

  2) 转换www.username.domain.com的对于username的主页请求为

  www.domain.com/username

  对于HTTP/1.1的请求包括一个Host: HTTP头,我们能用下面的规则集重写

  http://www.username.domain.com/anypath 到 /home/username/anypath

  Rewriteengine on

  rewritecond %{HTTP_HOST} ^www.[^.]+.host.com$

  rewriterule ^(.+) %{HTTP_HOST}$1 [C]

  rewriterule ^www.([^.]+).host.com(.*) /home/$1$2

  注:

  rewritecond 条件重写规则,当满足后面定义的条件后才会应用下面的重写规则,

  rewritecond有各种变量

  ,请查阅相关文件。

  3) 防火墙上的重写规则代理内部网段上服务器的请求。

  NameVirtualhost 1.2.3.4

  servername www.domain.com

  rewriteengine on

  proxyrequest on

  rewriterule ^/(.*)$ http://192.168.1.3/$1 [P,L]

  注:当外部浏览器请求www.domain.com时被解析到IP地址1.2.3.4 ,Apache 交出

  mod_rewrite处理转换成

  http://192.168.1.3/$1后再交由代理模块mod_proxy得到内容后传送回用户的浏览器。

  4) 基本预先设定的转换MAP表进行重写 rewritemap

  转换www.domain.com/{countrycode}/anypath Map表中规定的URI,上面是虚拟主机

  中的定义

  rewritelog /usr/local/apache/logs/rewrite.log

  rewriteloglevel 9

  rewriteengine on

  proxyrequest on

  rewritemap sitemap txt:/usr/local/apache/conf/rewrite.map

  rewriterule ^/([^/]+)+/(.*)$ http://%{REMOTE_HOST}::$1 [C]

  rewriterule (.*)::([a-z]+)$ ${sitemap:$2|http://h.i.j.k

你可能感兴趣的:(Apache Rewrite 详解)