.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 +FollowSymlinks
RewriteEngine 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

若访问
http://yourdomain.com/grab?file=my.zip
则会执行该页面:
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]
  • 将会把请求 /pages/123?one=two 映射到 /page.php?page=123&one=two
  • 注意粗体部分几乎是相同的,除了“问号”变成了“与”符号。
  • 如果没有 QS A标志,那么会映射到 /page.php?page=123
  • 如果没有用到小括号正则表达式,就不需要 QSA,这在上节“长短地址转换”中已经例证过了。
  • 小括号正则表达式可以截取查询字符串中的内容,但是如果没有开启 QSA 标志,那么在 /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 On
# Whatever 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/,读者必须对此多加小心;
  • 要想仅获得文件名,可以将 (.+) 替换成 ([^/]+),并且去掉符号 ^,如下所示:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !([^/]+)\.css$
RewriteCond %{REQUEST_FILENAME} !([^/]+)\.js$
RewriteRule ^(.+)$ /chat/ [NC]

2. 用 .htaccess 阻止 User-agent

什么是 User-agent?User-agent 用于浏览器向服务器“自报家门”,更确切的说是所有 HTTP 客户端都得用 User-agent 向服务器“自报家门”,以便服务器对不同的客户端作出不同响应。比如,某站点可能需要对浏览器、搜索引擎 crawl 还有各类下载工具作出不同的响应。服务器就是通过所谓的 User-agent 进行区分的。
如果你的服务器提供某些资源的下载,那么你就必须多加小心诸如“迅雷”等下载软件,因为它们可能把你网站资源吸干,并且影响你的正常访客访问。为此,我们可以利用 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)

盗链,特别是图片,是非常可耻的!哪怕将图片复制到自己服务器上,也比盗用他人的图片链接来得光彩!
.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 之间默认的逻辑连接词是逻辑“与”;
  • 这里的难点是理解逻辑转换,即德·摩根定律。

相关教程

1 Star2 Stars3 Stars4 Stars5 Stars (无评分)
Loading...

分类:一般问题 | 标签:

在线客服

QQ客服

微信客服