apache的url重写技术

14,046次阅读
没有评论

 

开启mod_rewrite
开启mod_rewrite模块
使用URL重写功能,需要安装mod_rewrite模块。使用phpinfo()函数,找到Apache Modules section部分,可以看到当前apache加载模块。
如果没有开启mod_rewrite, 就需要配置mod_rewrite.so的路径:
LoadModule rewrite_module modules/mod_rewrite.so
Apache2内置了mod_rewirte,在配置虚拟主机的配置文件VirtualHost部分打开引擎:RewriteEngine on
这句之后就可以使用重写语法了。
VirtualHost文件部分的Directory配置必须是:
<Directory />
Options Includes FollowSymLinks #允许使用符号链接
AllowOverride All #允许目录配置文件.htaccess。如果不使用是AllowOverride None
</ Directory>
利用mod_rewrite重写URL主要使用两个基本的指令RewriteRule和RewriteCond。
 
RewriteRule指令
RewriteRule Pattern Substitution [Flags]
在模式(Pattern)和替换(Substitution)中使用正则表达式来匹配相应的字符。
譬如有如下的URL:
http://www.example.com/display.php?country=USA &state=California&city=San_Diego
REQUEST_URI的值是“/country=USA &state=California&city=San_Diego”,要将国家州城市信息更友好的显示给用,要显示成这样:
http://www.example.com/USA/California/San_Diego
一个最常用的正则就是(.*)。它含有两个元素:一是“点”,表示任 意字符;二是“星”,表示以前的全部字符。所以(.*)会匹配{REQUEST_URI}的所有字符。Rewrite重写引擎的输入串是{REQUEST_URI},也就是URL中出去域名以及“?”符号后的所有查询字符。
重定向的URL中要提取出“USA/California/San_Diego”,匹配模式正则表达式的原型是:
(.*)/(.*)/(.*)
以上正则,在{REQUEST_URI}中通过两个“/”的分割存储了三个值,为了解决我们具体问题,我们得加一点限制――毕竟,第一个和最后一个原子可以匹配任何字符。
开始,我们可以添加一些特殊的字符,比如表示正则“开始”或者“结束”,“^”字符表示正则的开始而“$”表示正则的结束。
^(.*)/(.*)/(.*)$
{REQUEST_URI}是以“/”开头。Apache 在更改版本的时候会更改正则引擎,一代Apache要求有斜杠而二代Apache却不允许!但是我们可以用^/?(?表示匹配字符本身或者前一个字符)来兼容两个版本的Apache。再加上对字符匹配的限制,最终匹配模式是:
^/?([a-zA-Z_]+)/([a-zA-Z_]+)/([a-zA-Z_]+)$
完整表示如下:
RewriteEngine on
RewriteRule ^/?([a-zA-Z_]+)/([a-zA-Z_]+)/([a-zA-Z_]+)$ display.php?country=$1 &state=$2&city=$3 [L]
RewriteRule使用$1到$9引用模式()中匹配的内容,称为反向引用。对于URL:
http://www.example.com/USA/California/San_Diego
$1=USA,$2=California,$3=San_Diego
 
RewriteRule选项
"redirect|R[=code]" 强制重定向。经常引用到触发可见的定向。默认情况下它是一个HTTP 302的临时重定向,但是你可以注明具体的HTTP 代码,比如你可以用[R=301]来表明这是一个永久重定向,这对搜索引擎抓取你重定向后的网页相当有用。
"proxy|P"   强制为代理
"forbidden|F"   403 禁止。告诉Apache响应请求时不提供页面。其原理就是Apache会发出一个403 HTTP相应,可以保护网站不被未经授权的或者其他盗链访问。
"nocase|NC" 忽略正则表达式中的大小写。它经常被用到{HTTP_HOST}服务器参数上,因为域名里面是不会区分大小写的。
"next|N"    回到第一条规则。可以让你的重写条件循环匹配,当你不知道{REQUEST_URI}有多少字符进行匹配的时候很有用。
"last|L"    最后一个规则。告诉Apache服务器一系列的条件或者是规则将在它出现后结束,换句话说就是[L]不出现,mod_rewrite将会一直执行。
"noescape|NE"      在输出中不对URI作转义。此标记阻止mod_rewrite对重写结果应用常规的URI转义规则。 一般情况下,特殊字符(如‘%’, ‘$’, ‘;’等)会被转义为等值的十六进制编码。 此标记可以阻止这样的转义,以允许百分号等符号出现在输出中,如:
RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE]
可以使‘/foo/zed’转向到一个安全的请求‘/bar?arg=P1=zed’.
"skip|S=N" 跳过下面的N条规则。
 
RewriteCond指令
RewriteCond TestString CondPattern [Flags]
RewriteCond指令定义了一个规则的条件,即在一个RewriteRule指令之前有一个或多个RewriteCond指令。 条件之后的重写规则仅在当前URI与pattern匹配并且符合这些条件的时候才会起作用。
RewriteCond也有反向引用,但和RewriteRule中用$N引用不同,它使用%N反向引用。
RewriteCond引用Apache变量%{ NAME_OF_VARIABLE},如%{HTTP_HOST}。
RewriteCond的条件模式(CondPattern)除了使用perl样式正则表达式,还有额外的规则:
1.       使用‘!’ 字符(惊叹号)来实现匹配的反转
2.       ‘<CondPattern’ (词典顺序的小于)。将CondPattern视为纯字符串,与TestString以词典顺序相比较. 如果按词典顺序,TestString小于CondPattern,则为真。类似还有>,=。
3.       ‘-d’ (是一个目录[directory])。将TestString视为一个路径名并测试它是否存在而且是一个目录.
4.       ‘-f’ (是一个常规的文件[file])。将TestString视为一个路径名并测试它是否存在而且是一个常规的文件.
5.       ‘-s’ (是一个非空的常规文件[size])。将TestString视为一个路径名并测试它是否存在而且是一个尺寸大于0的常规的文件.
6.       ‘-l’ (是一个符号连接[link])。将TestString视为一个路径名并测试它是否存在而且是一个符号连接.
7.       ‘-F’ (对子请求有效的业已存在的文件)。测试TestString是否一个有效的文件, 而且可以被服务器当前已经配置的所有存取控制所存取。 它用一个内部子请求来做判断,由于会降低服务器的性能,请小心使用!
 
RewriteCond选项
‘nocase|NC’ (no case)。它使测试忽略大小写。此标记仅作用于TestString和CondPattern的比较, 而对文件系统和子请求的测试不起作用。
‘ornext|OR’ (or next condition)。它以OR方式组合若干规则的条件,而不是默认的AND。典型的例子如下:
RewriteCond %{REMOTE_HOST} ^host1.* [OR]
RewriteCond %{REMOTE_HOST} ^host2.* [OR]
RewriteCond %{REMOTE_HOST} ^host3.*
RewriteRule …some special stuff for any of these hosts…
如果不用这个标记,则必须使用三个 条件/规则。
 

服务器变量
HTTP变量
HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE,
HTTP_FORWARDED, HTTP_HOST, HTTP_PROXY_CONNECTION, HTTP_ACCEPT
连结和请求的变量
REMOTE_ADDR, REMOTE_HOST, REMOTE_USER, REMOTE_IDENT,
REQUEST_METHOD, SCRIPT_FILENAME, PATH_INFO, QUERY_STRING, AUTH_TYPE
服务器内部变量
DOCUMENT_ROOT, SERVER_ADMIN, SERVER_NAME, SERVER_ADDR,
SERVER_PORT, SERVER_PROTOCOL, SERVER_SOFTWARE
系统变量
TIME_YEAR, TIME_MON, TIME_DAY, TIME_HOUR,
TIME_MIN, TIME_SEC, TIME_WDAY, TIME
mod_rewrite特殊值
API_VERSION, THE_REQUEST, REQUEST_URI, REQUEST_FILENAME
 
URL重写举例
1.       给子域名加www标记
RewriteCond %{HTTP_HOST} ^([a-z.]+)?example\.com$ [NC]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .? http://www.%1example.com%{REQUEST_URI} [R=301,L]
这个规则抓取二级域名的%1变量,如果不是以www开始,那么就加www,以前的域名以及{REQUEST_URI}会跟在其后。
 
2.       去掉域名中的www标记
RewriteCond %{HTTP_HOST} !^example\.com$ [NC]
RewriteRule .? http://example.com%{REQUEST_URI} [R=301,L]
 
3.       去掉www标记,但是保存子域名
RewriteCond %{HTTP_HOST} ^www\.(([a-z0-9_]+\.)?example\.com)$ [NC]
RewriteRule .? http://%1%{REQUEST_URI} [R=301,L]
这里,当匹配到1%变量以后,子域名才会在%2(内部原子)中抓取到,而我们需要的正是这个%1变量。
 
4.       防止图片盗链
一些站长不择手段的将你的图片盗链在他们网站上,耗费你的带宽。你可以加一下代码阻止这种行为。
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?example\.com/ [NC]
RewriteRule \.(gif|jpg|png)$ – [F]
如果{HTTP_REFERER}值不为空,或者不是来自你自己的域名,这个规则用[F]FLAG阻止以gif|jpg|png 结尾的URL
如果对这种盗链你是坚决鄙视的,你还可以改变图片,让访问盗链网站的用户知道该网站正在盗用你的图片。
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?example\.com/.*$ [NC]
RewriteRule \.(gif|jpg|png)$ http://www.example.com/hotlinked.gif [R=301,L]
除了阻止图片盗链链接,以上规则将其盗链的图片全部替换成了你设置的图片。
你还可以阻止特定域名盗链你的图片:
RewriteCond %{HTTP_REFERER} !^http://(www\.)?leech_site\.com/ [NC]
RewriteRule \.(gif|jpg|png)$ – [F,L]
这个规则将阻止域名黑名单上所有的图片链接请求。
当然以上这些规则都是以{HTTP_REFERER}获取域名为基础的,如果你想改用成IP地址,用{REMOTE_ADDR}就可以了。
 
5.       如果文件不存在重定向到404页面
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule .? /404.php [L]
-f匹配的是存在的文件名,-d匹配的存在的路径名
 
6.       创建无文件后缀名链接
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.html [L]
如果文件是以.php为后缀,这条规则将被执行。
 
7.       强制使用HTTPS
RewriteCond %{HTTPS} !on
#RewriteCond %{SERVER_PORT} !^443$
RewriteCond %{HTTP_HOST} ^([a-z.]+)?example\.com$ [NC]
RewriteRule ^(.*)$  https://%1example.com$1 [R=301,L]
判断HTTPS服务可以判断安全端口(一般是443),也可以通过HTTPS变量。将example.com域名下所有url都强制使用https服务。
如果不判断域名,可以这样:
RewriteCond %{HTTPS} !on
RewriteRule ^/?(.*)$  https://%{SERVER_NAME}/$1 [R=301,L]
这里的$1前面有斜杠/,其实是匹配模式去掉了斜杠的原因,和上面效果是一样的。

什么是正则表达式?

正则表达式通常用来描述或者匹配一系列符合某个句法规则的字符串。比如^Colou?r$ 是一个用来匹配colorcolour这两个字符串的正则表达式。一枚正则表达式由字符和元字符组成。

什么是元字符?

元字符是正则表达式中具有特殊意义的字符。它们是正则表达式的基石。比如[], ^, (), {}, $, +, *等。

正则表达式的元字符:

[]

^

()

$

+

?

.

*

|

\

!

1. [] – 这个中括号用来匹配其内部的任何一个单字符,例如:

[a] => 匹配一个单字符,它是小写字母a.

[ab] => 匹配一个单字符,它是小写字母a或者b.

[aB] => 匹配一个单字符,它是小写字母a或者大写字母B.

[1B] => 匹配一个单字符,它是数字1或者大写字母B.

[Dog] => 匹配一个单字符:它是大写字母D,小写字母o或者小写字母g。

[123b] => 匹配一个单字符:它是数字1, 2, 3或小写字母g.

[1-3] => 匹配一个单字符,它是数字1, 2或者3。

[0-9] => 匹配一个单字符,它是一个数字。

[a-d] => 匹配一个单字符,它是小写字母a, b, c或者d。

[a-z] => 匹配一个单字符,它是一个小写字母。

[A-Z] => 匹配一个单字符,它是一个大写字母。

[home.php] => 匹配一个单字符,它是小写字母h,小写字母o,小写字母m,小写字母e,特殊字符.,小写字母p,小写字母h或者小写字母p。

2. ^ – 又叫“脱字符”,用来表示一段正则表达式的开始,例如:

^Colou?r => 匹配一个样本,该样本以Color或者Colour起头。

^Nov(ember)? => 匹配一个样本,该样本以Nov或者November起头。

^elearning*\.html => 匹配一个样本,该样本以elearning.html起头。

^\.php => 匹配一个样本,该样本以任意php文件起头。

^product-price\.php => 匹配一个样本,该样本以product-price.php起头。

脱字符跟随向右开口的中括号表示否定,例如:

[^a] => 匹配一个单字符,只要它不是小写字母a。

[^B] => 匹配一个单字符,只要它不是大写字母B。

[^1] => 匹配一个单字符,只要它是它不是数字1。

[^ab] => 匹配一个单字符,只要它不是小写字母a或b。

[^aB] => 匹配一个单字符,只要它不是小写字母a或大写字母B。

[^1B] => 匹配一个单字符,只要它不是数字1或者大写字母B。

[^Dog] => 匹配一个单字符,只要它不是大写字母D,小写字母o或者小写字母g。

[^123b] => 匹配一个单字符,只要它是它不是数字1,2,3或者小写字母b。

[^1-3] => 匹配一个单字符,只要它不是数字1,2或3。

[^0-9] => 匹配一个单字符,只要它不是数字。

[^a-z] => 匹配一个单字符,只要它不是小写字母。

[^A-Z] => 匹配一个单字符,只要它不是大写字母。

3. () – 圆括号用来匹配字符串,例如:

(a) => 匹配字符串a。

(ab) => 匹配字符串ab。

(dog) => 匹配字符串dog。

(dog123) => 匹配字符串dog123。

(0-9) => 匹配字符串0-9。

(A-Z) => 匹配字符串A-Z。

(a-z) => 匹配字符串a-z。

(123dog588) => 匹配字符串123dog588。

注意:()还被用来创造和储存变量。如:^(.*)$

4. $ – 用来标记一则表达式或者是一行的完结,例如:

Colou?r$ => 匹配一个样本,该样本以Color或者Colour结尾。

Nov(ember)?$ => 匹配一个样本,该样本以Nov或者November结尾。

elearning*\.html$ => 匹配一个样本,该样本以elearning.html结尾。

*\.php$ => 匹配一个样本,该样本以任意php文件结尾。

product-price\.php$ => 匹配一个样本,该样本以product-price.php结尾。

5. + – 一次或多次匹配前面的子字符,例如:

[a]+ => 一次或多次匹配小写字母a。

[dog]+ => 一次或者多次匹配小写字母d,o,或者g。

[548]+ => 一次或者多次匹配数字5,4或者8。

[0-9]+ => 一次或多次匹配数字。

[a-z]+ => 一次或多次匹配小写字母。

[^a-z]+ => 一次或者多次匹配非小写字母。

[a-zA-z]+ => 匹配任意的大小写字母组合。

[^9]+ => 一次或者多次匹配非9的字符。

6. ? – 零次或一次匹配前面的字符,例如:

[a]?+ => 零次或一次匹配小写字母a。

[dog]? => 零次或者一次匹配小写字母d,o,或者g。

[^dog]? => 零次或者一次匹配非小写字母d,o或者g。

[0-9]? => 零次或多次匹配数字。

[^a-z]? => 零次或多次匹配小写字母。

注意:在正则表达式中使用?表示之前的字母或者字母组可有可无。例如:正则表达式^COLOU?R$同时匹配COLOR和COLOUR。相似地,正则表达式^NOV(EMBER)28TH?$匹配:NOV 28,NOVEMBER 28,NOV 28TH和NOVEMBER 28TH。

7. . – 匹配非行尾的单字符,例如:

正则表达式Action.,Scene2匹配Action1,Scene2; Action A,Scene2; Action9,Scene2但却不匹配Action10,Scene2或者Action AB,Scene2。

8. * – 以任意次数(包括0次)匹配前面的字符,例如:

正则表达式31*将会匹配3,31,311,3111,31111等。

9. | – 表明逻辑,例如:

正则表达式(His|Her)匹配字符串his或者her。

10. \ – 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用,或一个八进制转义符,例如:

正则表达式^www\.abc\.com$匹配www.abc.com

11.! – 表明逻辑。但不像^(脱字符),它只在规则和条件的开头使用。例如:

(!abc) => 匹配非字符串abc。

[!0-9] => 匹配非数字的单字符。

[!a-z] => 匹配非小写字母的单字符。

一些正则表达式

^(*\.html)$ => 匹配.html前任意个数的字符并将其存入变量。

^dog$ => 匹配字符串dog。^a+$ => 一次或多次匹配小写字母a。

^(abc)+$ => 一次或多次匹配字符串abc。^[a-z]+$ => 一次或多次匹配小写字母。

^(abc)*$ => 以任意次数匹配字符串abc。

^a*$ => 以任意次数匹配小写字母a。

问:

找出所有以elearning开头并且包含.html扩展名的文件。
^elearning*\.html$

问:

找出所有的PHP文件。
^*\.php$

mod_rewrite

这是一个用C语言写的模块(功能):mod_rewrite.c。这个模块只能在Apache服务器1.2或之后的版本下工作同时被.htaccess文件执行(这是一个包含文件和文件夹配置指令和规则的ASCII文件)。通过这个模块你可以:

重写URL

重定向URL

解决正则URL问题

解决热链接问题

制作定制的403和404页面

基于IP地址提交内容,益处无穷

配置指令类型

总共有9种配置指令类型:

RewriteEngine

RewriteOptions

RewriteLog

RewriteLogLevel

RewriteLock

RewriteMap

RewriteBase

RewriteRule

RewriteCond

但在这里我们只讨论三种指令:RewriteEngine, RewriteRule和RewriteCond。我至今还没发现其他的指令有什么用。

但如果你想,其他的指令也会对SEO有所帮助。

REWRITEENGINE

这个配置指令用来激活或关闭mod_rewrite模块。

语法:RewriteEngine on/off

默认值:RewriteEngine off

这就是为什么在.htaccess文件中我们要加入下面的代码来激活mod_rewrite模块:

Options +FollowSymLinks

RewriteEngine on

REWRITERULE

这个配置指令告诉服务器将给定的语句编译成规则。

语法:Rewrite <pattern> <substitution> [FLAGS]

这里的pattern是一个正则表达式而substitution是一个URL.
FLAG可以是[R], [F], [NC], [QSA], [L], [OR]等。

[R] => 重定向。默认值为302。可以被赋予从300到400的任意数值,例如:

RewriteRule ^index\.html$/index.php [r=301]

[F] => 禁止。经常与连字符-一起使用。这个连字符告诉服务器不要进行任何替代。这个信号告诉服务器不要完成请求,同时返还一条403代码。例如:

RewriteRule ^product-price\.php$ -[F]

[NC] => 它告诉服务器在匹配样本时无视大小写。例如:

RewriteRule ^him*\.php$[nc][QSA] => 追加请求字符串(Query String Append)。它告诉服务器将字符串从旧的URL传递到新的。

[L] => 最后规则。这个标签告诉服务器不要再处理更多的规则了。

[OR] => 逻辑。这个标签用于RewriteCond声明中的逻辑或。

REWRITECOND

这个配置指令告诉服务器将一个给定的声明编译成立刻跟进的规则的一个条件。

语法:apache的url重写技术

这里第一个mod_rewrite将每一个URL和给定的样本进行匹配。如果没有URL符合样本,那么mod_rewrite就会执行下一条规则。如果有一条URL和样本匹配,那么mod_rewrite就会搜索相应的RewriteCond。

如果没有相应的RewriteCond存在,那么匹配的URL就会被替代。
如果相应的RewriteCond存在,那么每一条RewriteCond都会以从上到下的顺序被执行。服务器会将每一条RewriteCond的测试字符串和它相应的条件样本进行匹配。如果测试字符串与相应的条件样本不匹配,那么mod_rewrite就会执行下一条规则,否则就处理下一条RewriteCond。当所有的RewriteCond都成功处理完毕时,匹配的URL会被替代。测试字符串可以是:

简单文本

RewriteRule后方引用

RewriteCond后方引用

服务器变量

RewriteRule后方引用
形式为$N,这里的N可以是从0到9的任意数字。它用来标记在RewriteRule样本中被创建的变量,例如:

Rewrite ^(.*)$/index.php/$1 [L]

RewriteCond后方引用
形式为%N,这里的N可以是从1到9的任意数字。它用来标记从最后的匹配RewriteCond创建而来的在cond样本中的变量,例如:

RewriteCond %{HTTP_HOST} ^(123\.42\.162\.7)$ RewriteCond %1 ^123\.42\.162\.7$ RewriteRule .........

服务器变量

语法: % {Variable_Name}

例如:

%{HTTP_HOST} => 这个变量给出服务器信息以及其IP地址。

%{HTTP_USER_AGENT} => 这个变量给出用户操作系统和浏览器信息。

%{QUERY_STRING} => 这个变量返回查询字符串。

%{HTTP_REFERRER} => 这个变量返回来源的URL。

%{REMOTE_ADDR} => 这个变量返回来源的IP地址。

实例

实例一

将所有对media文件夹的页面请求重定向到亲的页面media.html

RewriteRule ^media/$/media.html [r=301,l]

实例二

oldaddress.html页面重定向至newaddress.html页面

RewriteRule ^oldaddress\.html$/newaddress.html [r=301,l]

实例三

将一个网址重定向至另一个网站

Redirect 301 http://www.anotherwebsite.com

实例四

禁止来自IP地址为12.34.56.78的访问者查看product-prices.html页面

RewriteCond %{REMOTE_ADDR} ^12\.34\.56\.78$ RewriteRule ^product-prices\.html$/sorry.html -[F]

实例五

abc.com/index.html重定向到www.abc.com

RewriteCond %{REQUEST_URL} ^index\.html$ RewriteRule ^(.*)$ http://www.abc.com/$1 [r=301,l]

实例六

阻止来自IP地址为12.34.56.78的访客查看sales-demo文件夹

RewriteCond %{REMOTE_ADDR} ^12\.34\.56\.78$ RewriteRule ^sales-demo/$ /sorry.html -[F]

实例七

阻止来自IP地址为12.34.56.78的访客访问你的网站www.abc.com

RewriteCond %{REMOTE_ADDR} ^12\.34\.56\.78$ RewriteRule ^.*$/ -[F]

.HTACCESS

这是一个包含了文件、文件夹和整个网站的配置指令以及规则的ASCII码文件。你能在一个服务器上拥有多个.htaccess文件。事实上每个文件夹和目录都能有一个.htaccess文件。当你将这个文件放置在某一文件夹中时,其中的规则仅对该文件夹及其子文件夹中的文件有效。当你将这个文件放置在根目录时,其中的规则适用于服务器上所有的文件夹和文件。一个有效的.htaccess文件必须包含以下两行代码:

Options +FollowSymLinks

RewriteEngine on

以上这些正则实例与SEO息息相关,是每一个SEO都应当掌握的基本知识。

Apache文档之mod_rewrite介绍:
Apache文档之URL重写指南:
正文完
 

公众号