URL重定向是.htaccess的重头戏,它可以将长地址转为短地址、将动态地址转为静态地址、重定向丢失的页面、防止盗链、实现自动语言转换等。笔者觉得难点是在正则表达式的运用和理解上。

实现所有这些神奇功能的模块叫做mod_rewrite,请确保你的服务器安装并启用了该模块:

sudo a2enmod rewrite

我们一般会把所有涉及URL重写或者重定向的代码这样放置:

<IfModule mod_rewrite.c>
# Turn on rewrite engine
Options +FollowSymlinks
RewriteEngine on
# More rules below
...
</IfModule>

一些我们需要注意的地方:

  • FollowSymlinks必须启用,这是rewrite引擎的安全需求。
  • 通常FollowSymlinks在Apache的主配置文件中就已经启用了,所以通常可以省略。
  • RewriteEngine命令用于启用rewrite引擎
  • IfModule命令用于判断Apache是否安装了mod_rewrite模块,之后笔者会省略该命令,但不代表这是个好习惯。
  • mod_rewrite会处理所有提交给Apache的URL请求,并与之后的规则进行匹配

二、利用.htaccess实现URL重写(rewrite)与URL重定向(redirect)

1.将.htm页面映射到.php

Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*)\.htm$ $1.php [NC]

注意事项:

  • 该RewriteRule能够将.htm静态页面映射到.php动态页面
  • 如果通过.htm进入,浏览器地址栏显示的是.htm扩展名,但服务器上实际执行的是.php
  • 必须保证服务器上有对应的.php,否则会404
  • 浏览器和搜索引擎可以同时通过.htm和.php访问网页
  • 如果该目录上存在.htm,将被忽略
  • [NC]表示“不区分大小写”,

2.临时重定向(R=302)与永久重定向(R=301)

RewriteEngine on
RewriteBase /
RewriteRule ^(.*)\.htm$ $1.php [R,NC,L]

注意事项:

  • 该RewriteRule能够将.htm静态页面重定向到.php动态页面
  • 如果通过.htm进入,浏览器地址栏会自动转为.php,这也是重定向的本质
  • 必须保证服务器上有对应的.php,否则会404
  • 浏览器和搜索引擎可以同时通过.htm和.php访问网页
  • 如果该目录上存在.htm,将被忽略
  • 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]
  • 字母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://mysite/grab?file=my.zip
则会执行该页面:
http://mysite/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]

7.支持多域名访问

如果你不凑巧买到了不支持多域名的主机,那么.htaccess或许可以帮助你。现在假设你有域名domain-one.com和domain-two.com,并且在服务器根目录有对应文件夹one和two,那么通过下面的改写就能让Apache同时接受者两个域名的请求:

#two domains served from one root..
RewriteCond %{HTTP_HOST} domain-one.com
RewriteCond %{REQUEST_URI} !^/one
RewriteRule ^(.*)$ /one/$1 [L] RewriteCond %{HTTP_HOST} domain-two.com
RewriteCond %{REQUEST_URI} !^/two
RewriteRule ^(.*)$ /two/$1 [L]

三、改写查询字符串QUERY_STRING

查询字符串是指URL请求中“问号”后面的部分。比如,http://mysite/grab?foo=bar中粗体部分就是查询字符串,其中变量名是foo,值是bar

1.利用QSA转换查询字符串QUERY_STRING

RewriteEngine On
RewriteRule /pages/(.+) /page.php?page=$1 [QSA]
  • 将会把请求/pages/123?one=two 映射到 /page.php?page=123&one=two
  • 注意粗体部分几乎是相同的,除了“问号”变成了“与”符号
  • 如果没有QSA标志,那么会映射到/page.php?page=123
  • 如果没有用到小括号正则表达式,就不需要QSA,这在上节“长短地址转换”中已经例证过了。
  • 小括号正则表达式可以截取查询字符串中的内容,但是如果没有开启QSA标志,那么在/page.php?page=$1中“问号”之后将会被剥离丢弃。这种特性可以用于实现“剥离查询字符串”

通过QSA,我们可以将简单链接/simple/flat/link/ 映射成 server-side.php?first-var=flat&second-var=link

RewriteEngine On
RewriteRule ^/([^/]+)/([^/]+)/? /index.php?first-var=$1&second-var=$2 [QSA]

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进行访问控制

1.文件访问控制

之前利用Order、Files及FilesMatch命令实现的访问控制可以满足大部分要求,但是当用户被拒绝时,他们看到的是硕大的“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
  • 该规则也会限制访问.htm, .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\.)?lesca\.me/ [NC]
RewriteCond %{REQUEST_URI} !hotlink\.png [NC]
RewriteRule .*\.(gif|jpg|png)$ /hotlink.png [NC]

简单解释一下该规则的功能:

  • 除本站以外其他网站都不得引用本站图片,具体可以理解为
  • 如果引用站点为“空”或者是“本站”,或者,所引用对象是“hotlink.png”,那么就允许访问
  • 再次提醒,RewriteCond之间默认的逻辑连接词是逻辑“与”
  • 这里的难点是理解逻辑转换,即德·摩根定律
 
转载至:作者: lesca http://lesca.me/archives/htaccess-rewrite.html

.htaccess技巧: URL重写(Rewrite)与重定向(Redirect)的更多相关文章

  1. .htaccess技巧: URL重写(Rewrite)与重定向(Redirect) (转)

    目录 Table of Contents 一.准备开始:mod_rewrite 二.利用.htaccess实现URL重写(rewrite)与URL重定向(redirect) 将.htm页面映射到.ph ...

  2. .htaccess技巧: URL重写(Rewrite)与重定向

    URL重定向是.htaccess的重头戏,它可以将长地址转为短地址.将动态地址转为静态地址.重定向丢失的页面.防止盗链.实现自动语言转换等.笔者觉得难点是在正则表达式的运用和理解上.有关htacces ...

  3. htaccess URL重写rewrite与重定向redirect(转)

    1. 将 .htm 页面映射到 .php 1 Options +FollowSymlinks 2 RewriteEngine on 3 RewriteRule ^(.*)\.htm$ $1.php [ ...

  4. openresty开发系列33--openresty执行流程之3重写rewrite和重定向

    openresty开发系列33--openresty执行流程之3重写rewrite和重定向 重写rewrite阶段 1)重定向2)内部,伪静态 先介绍一下if,rewrite指令 一)if指令语法:i ...

  5. .htaccess文件url重写小记

    .htaccess文件url重写 当上一条规则匹配 并转换后 符合下一条规则的 继续下一条的匹配转换 RewriteRule ^shangpin-([0-9a-zA-Z]+)/category-([0 ...

  6. nginx url重写 rewrite实例

    本文介绍下,在nginx中实现Url重写,学习rewrite的具体用法,有需要的朋友参考下吧. 原文地址:http://www.360doc.com/content/14/0202/20/142341 ...

  7. .htaccess伪静态(URL重写)绑定域名到子目录实现子站点

    Apache主机一般支持.htaccess伪静态,即可以实现绑定域名到子目录.一个空间多个站点. 应用举例:绑定htaccess.800m.net到htaccess目录 根目录下.htaccess内容 ...

  8. nginx的url重写[rewrite规则和参考]

    本日志内容来自互联网和平日使用经验,整理一下方便日后参考. Nginx Rewrite 相关指令有 if.rewrite.set.return 等. if 的语法 应用于 server 和 locat ...

  9. 很不错的NGINX URL重写实例

    转自:http://www.jbxue.com/article/2187.html 本文介绍nginx URL重写的相关知识,包括301重定向的内容等,希望对大家有所帮助. nginx rewrite ...

随机推荐

  1. C++解析(16):友元与类中的函数重载

    0.目录 1.友元的尴尬能力 2.类中的函数重载 3.小结 1.友元的尴尬能力 什么是友元? 友元是C++中的一种关系 友元关系发生在函数与类之间或者类与类之间 友元关系是单项的,不能传递 友元的用法 ...

  2. DelayQueue实现Java延时任务

    最近公司需要实现一个订单超时自动关闭的功能,由Java这块来实现 一开始我以为就是定时任务,深入了解了之后发现并不是,官方名称应该叫延时任务,到时间之后 执行传过来的回调函数 这个功能我一共前前后后写 ...

  3. 代码收藏系列--mysql--创建数据库、数据表、函数、存储过程命令

    创建mysql数据库 CREATE DATABASE IF NOT EXISTS `database_name` DEFAULT CHARSET utf8 COLLATE utf8_general_c ...

  4. 序列计数(count)

    Portal -->broken qwq Description ​​  给你一个长度为\(n\)的序列,序列中的每个数都是不超过\(m\)的正整数,求满足以下两个条件的序列数量: 1.序列中至 ...

  5. C语言 结构体作为参数和返回值使用

    方案一:结构体变量作为参数,进行传值. 编译器需要拷贝,不影响origin value,使用成员操作符(.)直接访问 /**************************************** ...

  6. OpenCV---直方图反向投影

    一:直方图反向投影的方法 二:二维直方图的表示 (一)直接显示 def hist2D_demo(image): hsv = cv.cvtColor(image,cv.COLOR_BGR2HSV) hi ...

  7. Thinkphp关联模型使用

    1.需求描述 首页文章列表,需要同时获取文章的点赞和被关注数,同时如果被当前用户点赞或关注了会显示相应小图标进行区别.图示如下: 2.解决方案 数据库设计: 文章对应Article表,其中包括收藏数字 ...

  8. CF835 D DP

    所有所有阶回文串的个数.对于一个k阶回文串,定义为:它的左右两侧相同且是k-1阶回文串 显然高阶回文串由低阶构成,那么枚举长度,从左到右遍历,dp[l][r]代表从l到r串最大的阶数,cnt[i]记录 ...

  9. Shell编程——bash基础知识

    # Bash中自动补全时忽略大小写 # 编辑~/.inputrc(没有的话,就新建一个),在最后加一行: set completion-ignore-case on # 若要用方向键Up,Down来搜 ...

  10. 【CodeForces】901 C. Bipartite Segments

    [题目]C. Bipartite Segments [题意]给定n个点m条边的无向连通图,保证不存在偶数长度的简单环.每次询问区间[l,r]中包含多少子区间[x,y]满足只保留[x,y]之间的点和边构 ...