zoukankan      html  css  js  c++  java
  • .htaccess技巧: URL重写(Rewrite)与重定向

    (转)https://www.cnblogs.com/wang1204/p/6392602.html

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

    一、准备开始:mod_rewrite

    实现所有这些神奇功能的模块叫做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]表示“不区分大小写”,更多类似定义请参考本站《.htaccess正则表达式》一文

    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]。关于重定向代码,请参考《HTTP协议重定向编码
    • 字母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

    QSA标志( Query String Appending)用于在URI中截取查询字符串,这个截取操作是通过小括号正则表达式实现的:

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

    我们在第一篇.htaccess基础中提到了很多有用的访问控制方法,其实通过Rewrite也能实现类似的功能,而且可以更强大!

    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之间默认的逻辑连接词是逻辑“与”
    • 这里的难点是理解逻辑转换,即德·摩根定律
    当你发现自己的才华撑不起野心时,就请安静下来学习吧
  • 相关阅读:
    LeetCode Flatten Binary Tree to Linked List
    LeetCode Longest Common Prefix
    LeetCode Trapping Rain Water
    LeetCode Add Binary
    LeetCode Subsets
    LeetCode Palindrome Number
    LeetCode Count and Say
    LeetCode Valid Parentheses
    LeetCode Length of Last Word
    LeetCode Minimum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/alexguoyihao/p/9259230.html
Copyright © 2011-2022 走看看