.htaccess 教程:URL 重写(Rewrite)与重定向(Redirect)
URL 重定向是 .htaccess 的重头戏,它可以将长地址转为短地址、将动态地址转为静态地址、重定向丢失的页面、防止盗链、实现自动语言转换等。难点是在正则表达式的运用和理解上。有关 htaccess 的正则表达式用法,可以参考下面的教程:
一、准备开始:mod_rewrite
实现所有这些神奇功能的模块叫做 mod_rewrite,请确保你的服务器安装并启用了该模块,老薛主机所有云主机已经启用该模块,可以直接使用。
我们一般会把所有涉及URL重写或者重定向的代码这样放置:
# Turn on rewrite engine Options +FollowSymlinks RewriteEngine on # More rules below ...
一些我们需要注意的地方:
FollowSymlinks 必须启用,这是 rewrite 引擎的安全需求。
通常 FollowSymlinks 在 Apache 的主配置文件中就已经启用了,所以通常可以省略。
RewriteEngine 命令用于启用 rewrite 引擎
IfModule 命令用于判断 Apache 是否安装了 mod_rewrite 模块,之后我们会省略该命令,但不代表这是个好习惯。
mod_rewrite 会处理所有提交给 Apache 的 URL 请求,并与之后的规则进行匹配。
下面我们开始讲解一些例子。
二、利用 .htaccess 实现 URL 重写(rewrite)与 URL 重定向(redirect)
1. 将 .html 页面映射到 .php
Options +FollowSymlinksRewriteEngine on
RewriteRule ^(.*).html$ $1.php [NC]
注意事项:
该 RewriteRule 能够将 .html 静态页面映射到 .php 动态页面。
如果通过 .html 进入,浏览器地址栏显示的是 .html 扩展名,但服务器上实际执行的是 .php。
必须保证服务器上有对应的 .php,否则会 404。
浏览器和搜索引擎可以同时通过 .html 和 .php 访问网页。
如果该目录上存在 .html,将被忽略。
[NC] 表示“不区分大小写”,更多类似定义请参考:https://help.laoxuehost.com/other-help/htaccess-regular-expression.html
2. 临时重定向(R=302)与永久重定向(R=301)
RewriteEngine on
RewriteBase /
RewriteRule ^(.*).html$ $1.php [R,NC,L]
注意事项:
该 RewriteRule 能够将 .html 静态页面重定向到 .php 动态页面。
如果通过 .html 进入,浏览器地址栏会自动转为 .php,这也是重定向的本质。
必须保证服务器上有对应的 .php,否则会 404。
浏览器和搜索引擎可以同时通过 .html 和 .php 访问网页。
如果该目录上存在 .html,将被忽略。
RewriteBase定义了重写基准目录,
例如,如果你将虚拟站点设置在 /var/www 目录下,删除这行将会导致重定向到 http://yourdomain.com/var/www/1.php 。显然这是找不到的,而且你也不会希望用户看见你的服务器的目录结构;
再举个例子,如果 RewriteBase /base/,那么将会重定向到 http://yourdomain.com/base/1.php 。
对于重写基准目录,我们还可以通过将 $1.php 变成 /$1.php 实现直接变换,这时就可以将 RewriteBase 省略。
字母 R 表示临时重定向,相当于 [R=302,NC] ,关于重定向代码,请参考:https://help.laoxuehost.com/other-help/htaccess-regular-expression.html
字母 L 表示如果能匹配本条规则,那么本条规则是最后一条 (Last),忽略之后的规则。
在讨论 R=302 临时重定向后,理解 R=301 永久重定向也就容易多了:
RewriteEngine on
RewriteRule ^(.*)$ http://newdomain.com/$1 [R=301,NC,L]
这个规则告诉浏览器和搜索引擎,网站地址发生了永久性变更,用户的 URL 请求将会被发送给新的域名(主机)处理。
由于是重定向到新的主机地址,RewriteBase 也就没有出现的必要了。
3. 为什么要用重定向?——重定向和 URL 重写的区别
通过重定向,浏览器知道页面位置发生变化,从而改变地址栏显示的地址;
通过重定向,搜索引擎意识到页面被移动了,从而更新搜索引擎索引,将原来失效的链接从搜索结果中移除;
临时重定向 (R=302) 和永久重定向 (R=301) 都是亲搜索引擎的,是 SEO 的重要技术;
URL 重写用于将页面映射到本站另一页面,若重写到另一网络主机(域名),则按重定向处理。
4. 长短地址转换
利用 URL 重写,我们可以很方便地实现长短地址的转换,但是用重定向就不合适了。
RewriteEngine On
RewriteRule ^grab /public/files/download/download.php
若访问<br/>http://yourdomain.com/grab?file=my.zip<br/>则会执行该页面:<br/>http://yourdomain.com/public/files/download/download.php?file=my.zip
5. 去掉 www
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www.(.*) [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,NC,L]
6. 加上 www
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(.*)$
RewriteRule (.*) http://www.%1/$1 [R=301,L]
三、改写查询字符串 QUERY_STRING
查询字符串是指 URL 请求中“问号”后面的部分。比如,http://mysite/grab?foo=bar 中粗体部分就是查询字符串,其中变量名是 foo,值是 bar。
1. 利用 QSA 转换查询字符串 QUERY_STRING
QSA 标志( Query String Appending)用于在 URI 中截取查询字符串,这个截取操作是通过小括号正则表达式实现的:
RewriteEngine On
RewriteRule /pages/(.+) /page.php?page=$1 [QSA]</pre><ul style="box-sizing: border-box; font-family: 微软雅黑, 幼圆, "Lucida Grande", Verdana, Arial, sans-serif; font-size: 12.8px; white-space: normal; background-color: rgb(255, 255, 255);" class=" list-paddingleft-2"><li><p>将会把请求 /pages/<strong>123?one=two</strong> 映射到 /page.php?page=<strong>123&one=two</strong> 。</p></li><li><p>注意粗体部分几乎是相同的,除了“问号”变成了“与”符号。</p></li><li><p>如果没有 QS A标志,那么会映射到 /page.php?page=<strong>123</strong> 。</p></li><li><p>如果没有用到<strong>小括号正则表达式</strong>,就不需要 <strong>QSA</strong>,这在上节“长短地址转换”中已经例证过了。</p></li><li><p><strong>小括号正则表达式</strong>可以截取查询字符串中的内容,但是如果没有开启 <strong>QSA</strong> 标志,那么在 <strong>/page.php?page=$1 中“问号”之后将会被剥离丢弃。这种特性可以用于实现“剥离查询字符串”通过 QSA,我们可以将简单链接 /simple/flat/link/ 映射成 server-side.php?first-var=flat&second-var=link
2. 利用 RewriteCond 改写查询字符串 QUERY_STRING
RewriteEngine On
RewriteCond %{QUERY_STRING} foo=(.*)
RewriteRule ^grab(.*) /page.php?bar=%1
该规则将访问请求 http://mysite/grab?foo=bar 转换为 http://mysite/page.php?bar=bar 。
RewriteCond 用于捕获查询字符串(QUERY_STRING)中变量 foo 的值,并存储在 %1 中。
QUERY_STRING 是 Apache 定义的“变量=值”向量(数组)。
3. QSA 与 RewriteCond 双剑齐发
RewriteEngine On
RewriteCond %{QUERY_STRING} foo=(.+)
RewriteRule ^grab/(.*) /%1/index.php?file=$1 [QSA]
会把 /grab/foobar.zip?level=5&foo=bar 映射到 /bar/index.php?file=foobar.zip&level=5&foo=bar 。
转换后根目录是 bar 目录。
foobar.zip?level=5 中的“问号”变成了 foobar.zip&level=5 中的“与”符号。
4. 剥离查询字符串
只需在要开始剥离的链接后面加个“问号”,并且不要启用 QSA 标志,就可剥离查询字符串。
RewriteEngine OnWhatever QS is
RewriteCond %{QUERY_STRING} .
I don't want it with Question mark
RewriteRule foo.php(.*) /foo.php? [L]
四、利用 RewriteCond 和 RewriteRule 进行访问控制
我们在另外一篇教程中提到了很多有用的访问控制方法,具体可以查看:https://help.laoxuehost.com/other-help/htaccess-basic.html,其实通过 Rewrite 也能实现类似的功能,而且可以更强大!
1. 文件访问控制
利用 Order、Files 及 FilesMatch 命令实现的访问控制可以满足大部分要求(具体可以查看:https://help.laoxuehost.com/other-help/htaccess-basic.html),但是当用户被拒绝时,他们看到的是硕大的“403 Forbidden”,如果你不想伤害用户的感情,就需要显示一些别的东西,通过 Rewrite 就可以实现这个特性:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !^(.+).css$
RewriteCond %{REQUEST_FILENAME} !^(.+).js$
RewriteCond %{REQUEST_FILENAME} !special.zip$
RewriteRule ^(.+)$ /chat/ [NC]
该规则将仅允许用户请求 .css, .js 类型的文件,还有 special.zip 文件;
RewriteRule 后面指定了限制规则:映射到 /char/ 目录下处理;
RewriteCond 后面的“感叹号”(!)起到了“否定”作用,它表明,对不满足后面正则表达式者应用 RewriteRule 规则,也就是对当前类型的文件将不应用规则;
RewriteCond 之间是以逻辑“与”连接的,也就是只有当三个条件都不满足时才执行 RewriteRule;
该规则也会限制访问 .html, .jpg 等格式;
该规则不可以放在虚拟站点根目录(/)下,否则会死循环;
如果是二级目录,如 /test/,那么传入 RewriteCond 的参数是以 /test/ 开始的,因此从 (.+) 获得的文件名也含有 /test/,读者必须对此多加小心;
要想仅获得文件名,可以将 (.+) 替换成 (1+),并且去掉符号 ^,如下所示:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !(1+).css$
RewriteCond %{REQUEST_FILENAME} !(1+).js$
RewriteRule ^(.+)$ /chat/ [NC]
2. 用 .htaccess 阻止 User-agent
什么是 User-agent?User-agent 用于浏览器向服务器“自报家门”,更确切的说是所有 HTTP 客户端都得用 User-agent 向服务器“自报家门”,以便服务器对不同的客户端作出不同响应。比如,某站点可能需要对浏览器、搜索引擎 crawl 还有各类下载工具作出不同的响应。服务器就是通过所谓的 User-agent 进行区分的。<br/>如果你的服务器提供某些资源的下载,那么你就必须多加小心诸如“迅雷”等下载软件,因为它们可能把你网站资源吸干,并且影响你的正常访客访问。为此,我们可以利用 Rewrite 限制某些 UA 的访问:
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} 2.0.50727 [NC]
RewriteRule . abuse.txt [L]
该规则限制“迅雷”客户端下载资源,并将下载文件重置到 abuse.txt ;
HTTP_USER_AGENT 是 Apache 的内置变量;
2.0.50727 是迅雷 User-agent 的特征字符串;
RewriteRule 后面的“点”表示“任意 URI”,也就是不管请求的是什么,都输出 abuse.txt 。
通常,我们不会仅限制一个 UA。利用 [OR] 即可实现对多个 UA 作出统一处理:
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} 2.0.50727 [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^BlackWidow [NC,OR]etc..
RewriteCond %{HTTP_USER_AGENT} ^Net\ Vampire [NC]
RewriteRule . abuse.txt [L]
3. 用 .htaccess 阻止盗链 (hot-linking)
盗链,特别是图片,是非常可耻的!哪怕将图片复制到自己服务器上,也比盗用他人的图片链接来得光彩!<br/>.htaccess 的 Rewrite 功能可以提供非常简单、有效的方法阻止这种可耻行为:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www.)?domain.com/ [NC]
RewriteCond %{REQUEST_URI} !hotlink.png [NC]
RewriteRule .*.(gif|jpg|png)$ /hotlink.png [NC]
简单解释一下该规则的功能:
除域名(domain.com)以外其他网站都不得引用本站图片,具体可以理解为;
如果引用站点为“空”或者是“本站”,或者,所引用对象是“hotlink.png”,那么就允许访问;
再次提醒,RewriteCond 之间默认的逻辑连接词是逻辑“与”;
这里的难点是理解逻辑转换,即德·摩根定律。
相关教程
.htaccess 教程:简介、访问控制、验证、目录浏览控制
.htaccess 教程:正则表达式、重定向代码
<br/>
- / ↩