1、Rewrite 规则简介

Rewirte主要的功能就是实现URL的跳转,它的正则表达式是基于Perl语言。

.    换行符"/n"以外的所有字符
\w   匹配字母或数字或下划线或汉字
\s   匹配任意的空白符
\d   匹配数字
\b   匹配单词的开始或结束
 ^   匹配字符串的开始
 $   匹配字符串的结束
 *   重复零次或更多次
 +   重复一次或更多次
 ?   重复零次或一次
 {n}         重复n次
 {n,}        重复n次或更多次
 {n,m}       重复n到m次
 () $1 $2    一个括号代表一个分组,第一个括号里匹配的内容就用$1引用,第二个括号匹配的内容用$2引用,以此类推...

更多正则表达式,请见米扑博客:正则表达式的学习与小结

 

Rewrite 可基于服务器级的(httpd.conf)和目录级的(.htaccess)两种方式,本文最后分别有示例。

如果要想用到rewrite模块,必须先安装或加载rewrite模块,方法有两种:

一种是编译apache的时候就直接安装rewrite模块,

另一种是编译apache时以DSO模式安装apache,然后再利用源码和apxs来安装rewrite模块。

启动apache前需开启 rewrite 模块,httpd.conf 文件中

LoadModule rewrite_module modules/mod_rewrite.so  // 去除前面的"#"号; 

 

基于服务器级的(httpd.conf)有两种方法:

一种是在httpd.conf的全局下直接利用RewriteEngine on来打开rewrite功能;

另一种是在局部里(如:<VirtualHost *:80>)利用RewriteEngine on来打开rewrite功能

下面将会举例说明,需要注意的是,必须在每个VirtualHost里用RewriteEngine on来打开rewrite功能,否则VirtualHost里没有RewriteEngine on,它里面的规则也不会生效。

基于目录级的(.htaccess),要注意一点那就是必须打开此目录的FollowSymLinks属性(httpd.conf中的Option FollowSymLinks)且在.htaccess里要声明RewriteEngine on。

<IfModule mod_rewrite.c>
RewriteEngine On
 
# Redirect
Options +FollowSymLinks
RewriteCond %{HTTP_HOST}   !^(.*)mimvp\.com(.*)$ [NC]
RewriteRule ^(.*)$ https://blog.mimvp.com/$1 [R=301,L]

...

</IfModule>

 

2、Apache mod_rewrite 规则中的标记含义

1)RewriteRule 重写控制

RewriteRule 重写规则的表达式:RewriteRule 匹配模式 替换重定向 [选项]​

[选项] 重写规则有

'forbidden' 或 'f' - 403 禁止
'gone' 或 'g' - 410 gone
'nocase' 或 'NC' - 大小写敏感
'next'/N' - 回到第一条规则
'skip=N' 或 'S=N' - 跳过下面的N条规则

 

RewriteRule [选项]​

 
RewriteRule标记 含 义 描 述
R Redirect 发出一个HTTP重定向
F Forbidden 禁止对URL地址的存取
G Gone 标记URL地址不存在
P Proxy 将URL地址传递给mod_proxy
L Last 停止处理接下来的规则
N Next 再次重第一个规则开始处理,但是使用当前重写后的URL地址
C Chain 将当前的规则和紧随其后的规则链接起来
T Type 强制执行指明的MIME类
NS Nosubreq 只在没有任何内部子请求执行时运行本脚本
NC Nocase URL地址匹配对大小写不敏感
QSA Qsappend 在新的URL地址后附加查询字符串部分,而不是替代
PT Passthrough 将重写后的URL地址传递给另一个Apache模块进行进一步处理
S Skip 忽略之后的规则
E Env 设置环境变量

 

2)RewriteCond 流程控制

RewriteCond 流程控制格式是:RewriteCond 测试条件 Condition

mod_rewrite是按照从上到下的顺序执行重写的规则,如果URL匹配了第一条规则(RewriteCond),则按照第一条规则进行重写;如果不匹配,就执行第二条规则,直到最后。通过流程控制,可以定义在不同情况下采用不同的重写规则。

RewriteCond 测试条件有:

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

例如,利用mod_rewrite可以禁止从其他的网站链接到你的图片(防盗链):

## 防盗链
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !^(.*)mimvp.com [NC]
RewriteCond %{HTTP_REFERER} !^(.*)baidu.com [NC]
RewriteCond %{HTTP_REFERER} !^(.*)sogou.com [NC]
RewriteCond %{HTTP_REFERER} !^(.*)so.com [NC]
RewriteCond %{HTTP_REFERER} !^(.*)bing.com [NC]
RewriteCond %{HTTP_REFERER} !^(.*)google.com [NC]
RewriteRule .*\.(png|gif|jpg|jpeg|bmp|swf|pdf|txt|zip|rar)$ /anti-link.jpg [L,NC]

 

这里,要重点说明下 RewriteCond 的逻辑运算:AND、OR、NC

1)AND 是 RewriteCond 多个条件的与运算,默认的,不需要显式给出

2)OR 是多个 RewriteCond 的或运算,符合任一个条件,则执行规则

3)NC 是指不区分大小,有时 URL 链接里会有大小写,不做区分

示例解释说明

conf/httpd.conf 中 RewriteCond 末尾添加 [NC]为不区分大写

RewriteCond 语句之间默认的是AND,如果想要或 OR,则要明确的写出来

示例1

NameVirtualHost *:80  
<VirtualHost *:80>     
    ServerName mimvp.com  
    DirectoryIndex index.php index.html index.htm  
    
	<IfModule rewrite_module>  
		RewriteEngine On  
		RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/5.0.* [NC]  
		RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/3.0.* [NC]  
		RewriteRule ^/   https://mimvp.com/   

		RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/4.0.* [NC]  
		RewriteRule ^/   http://www.mimvp.net/   
	</IfModule>  
</VirtualHost> 

其对应的伪代码逻辑

if(HTTP_USER_AGENT.startWith("Mozilla/5.0") && HTTP_USER_AGENT.startWith("Mozilla/3.0")){  
	System.out.println("https://mimvp.com/");  
}  

if(HTTP_USER_AGENT.startWith("Mozilla/4.0")){  
	System.out.println("https://www.mimvp.net/");  
}  

由上可见,RewriteCond 之间默认是 AND (&&)与逻辑

 

示例2

<IfModule rewrite_module>  
	RewriteEngine On  
	RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/5.0.* [NC]  
	RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/3.0.* [NC,OR]  
	RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/4.0.* [NC]  
	RewriteRule ^/   https://mimvp.com/   
</IfModule>  	

其对应的伪代码逻辑

if( (HTTP_USER_AGENT.startWith("Mozilla/5.0") && HTTP_USER_AGENT.startWith("Mozilla/3.0")) 
	|| (HTTP_USER_AGENT.startWith("Mozilla/4.0")){  
	System.out.println("https://mimvp.com/ ");  
}  

由上可见,RewriteCond 之间 OR (||)或逻辑,需要显式给出,并依次向下或逻辑

 

3)Rewrite 参数配置详解

强制在替代字符串加上http://thishost[:thisport]/前缀重定向到外部的URL.如果code不指定,将用缺省的302 HTTP状态码。

1) R[=code](force redirect) 强制外部重定向

2) F(force URL to be forbidden)禁用URL,返回403 HTTP状态码。
3) G(force URL to be gone) 强制URL为GONE,返回410 HTTP状态码。
4) P(force proxy) 强制使用代理转发。
5) L(last rule) 表明当前规则是最后一条规则,停止分析以后规则的重写。
6) N(next round) 重新从第一条规则开始运行重写过程。
7) C(chained with next rule) 与下一条规则关联

如果规则匹配则正常处理,该标志无效,如果不匹配,那么下面所有关联的规则都跳过。

8) T=MIME-type(force MIME type) 强制MIME类型
9) NS (used only if no internal sub-request) 只用于不是内部子请求
10) NC(no case) 不区分大小写
11) QSA(query string append) 追加请求字符串
12) NE(no URI escaping of output) 不在输出转义特殊字符

例如:

RewriteRule /foo/(.*) /bar?arg=P1%3d$1 [R,NE]   // 将能正确的将/foo/zoo转换成/bar?arg=P1=zoo

13) PT(pass through to next handler) 传递给下一个处理

例如:

RewriteRule ^/abc(.*) /def$1 [PT]  # 将会交给/def规则处理
Alias /def /ghi
14) S=num(skip next rule(s)) 跳过num条规则
15) E=VAR:VAL(set environment variable) 设置环境变量

 

3、举例说明

例一、把client请求的主机前缀不是www.mimvp.com和47.106.126.167都跳转到主机前缀为http://www.mimvp.com,避免相同内容的网页有多个指向的域名,如http://mimvp.com

RewriteEngine on 								# 打开 rewirte 功能
RewriteCond %{HTTP_HOST} !^$ 					# 声明Client请求的主机中前缀不为空
RewriteCond %{HTTP_HOST} !^www.mimvp.com [NC] 	# 请求的主机中前缀不是www.mimvp.com,[NC]是忽略大小写
RewriteCond %{HTTP_HOST} !^47.106.126.167 [NC] 	# 请求的主机中前缀不是47.106.126.167,[NC]是忽略大小写
RewriteRule ^(.*) http://www.mimvp.com/ [L] 	# 强制重定向到米扑科技首页

解释说明:

最后一句 RewriteRule ^(.*) http://www.mimvp.com/ [L] 含义是如果Client请求的主机中的前缀符合上述条件,则直接进行跳转到http://www.mimvp.com/,[L]表示最后一次匹配,立即停止重写操作,并不再应用执行其他重写规则。这里的.*是指匹配所有URL中不包含换行字符,()括号的功能是把所有的字符做一个标记,以便于后面的应用,本例里并没有应用到$1,其就是引用前面里的(.*)字符。

 

例二、将输入 study.mimvp.com 的域名时跳转到www.mimvp.com

RewriteEngine on
RewriteCond %{HTTP_HOST} ^study.mimvp.com [NC]
RewriteRule ^(.*) http://www.mimvp.com/$1 [L]

最后一句 RewriteRule ^(.*) http://www.mimvp.com/$1 [L] 含义是把 study.mimvp.com 跳转到了 www.mimvp.co,并把 (.*) 传递给了 $1

 

例三、将原来的域名ss.mimvp.com, 以及论坛所在地址ss.mimvp.com/bbs/定向到新的域名,以便用户可以找到,并且使原来的论坛 URL 继续有效而不出现 404 未找到

比如原来的http://ss.mimvp.com/bbs/tread-60.html,让它在新的域名下继续有效,不跳转,点击后转发到http://bbs.mimvp.com/tread-60.html

而其他网页(路径非 /bbs/),如原先的http://ss.mimvp.com/purchase不会到二级域名bbs.mimvp.com/purchase上,而是到www.mimvp.com/purchase

按照这样的要求重定向规则应该这样写:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/bbs/		# 路径是 /bbs/,仍然有效,不跳转
RewriteRule ^bbs/(.*) http://bbs.mimvp.com/$1 [R=permanent,L]
RewriteCond %{REQUEST_URI} !^/bbs/		# 路径非 /bbs/,跳转到 www.mimvp.com
RewriteRule ^(.*) http://www.mimvp.com/$1 [R=permanent,L]

 

例四、同时达到下面两个要求:

1. 用http://www.mimvp.com/xxx.php 来访问 http://www.mimvp.com/xxx/
2. 用http://yyy.mimvp.com 来访问 http://www.mimvp.com/user.php?username=yyy 的功能

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.mimvp.com
RewriteCond %{REQUEST_URI} !^user.php$
RewriteCond %{REQUEST_URI} .php$
RewriteRule (.*).php$ http://www.mimvp.com/$1/ [R]	# 同时满足上面三个条件(RewriteCond)
RewriteCond %{HTTP_HOST} !^www.mimvp.com
RewriteRule ^(.+) %{HTTP_HOST} [C]					# [C] 表示执行本规则后,继续执行下面的规则
RewriteRule ^([^.]+).mimvp.com http://www.mimvp.com/user.php?username=$1

 

例五、伪静态跳转

单参数动态请求跳转 /type.php?typeid=* –> /type*.html
多参数动态请求跳转 /type.php?typeid=*&page=* –> /type*page*.html

RewriteRule ^/type([0-9]+).html$ /type.php?typeid=$1 [PT]
RewriteRule ^/type([0-9]+)page([0-9]+).html$ /type.php?typeid=$1&page=$2 [PT]

 

例六、使用Apache的URL Rewrite配置多用户虚拟服务器

要实现这个功能,首先要在DNS服务器上打开域名的泛域名解析(自己做或者找域名服务商做)。

比如,我就把 *.mimji.com和 *.mimvp.com全部解析到了我的IP地址47.106.126.167上。

然后,看一下我的Apache中关于*.mimji.com的虚拟主机的设定。

ServerAdmin webmaster@mimji.com
DocumentRoot /home/www/www.mimji.com
ServerName dns.mimji.com
ServerAlias dns.mimji.com mimji.com *.mimji.com
CustomLog /var/log/httpd/osa/access_log.log” common
ErrorLog /var/log/httpd/osa/error_log.log”
AllowOverride None
Order deny,allow
#AddDefaultCharset UTF-8
RewriteEngine on
RewriteCond %{HTTP_HOST} ^[^.]+.mimvp.(com|cn|us)$
RewriteRule ^(.+) %{HTTP_HOST}$1 [C]
RewriteRule ^([^.]+).mimvp.(com|cn|us)(.*)$ /home/www/www.mimji.com/sylvan$3?un=$1&%{QUERY_STRING} [L]

 

在这段设定中,我把*.mimvp.com和*.mimji.com 的Document Root都设定到了 /home/www/www.mimji.com

继续看下去,在这里我就配置了URL Rewrite规则。

RewriteEngine on 										# 打开URL Rewrite功能
RewriteCond %{HTTP_HOST} ^[^.]+.mimvp.(com|cn|us)$ 		# 匹配条件,如果用户输入的URL中主机名是类似 xxxx.mimji.com 或者 xxxx.mimvp.com 就执行下面一句
RewriteRule ^(.+) %{HTTP_HOST}$1 [C] 					# 把用户输入完整的地址(GET方式的参数除外)作为参数传给下一个规则,[C]是Chain串联下一个规则的意思
RewriteRule ^([^.]+).mimvp.(com|cn|us)(.*)$ /home/www/dev.mimji.com/sylvan$3?un=$1&%{QUERY_STRING} [L]

解释说明:

最关键的是最后一句,使用证则表达式解析用户输入的URL地址,把主机名中的用户名信息作为名为un的参数传给/home/www/dev.mimji.com目录下的脚本,并在后面跟上用户输入的GET方式的传入参数。并指明这是最后一条规则([L] 规则)。注意,在这一句中指明的重写后的地址用的是服务器上的绝对路径,这是内部跳转。如果使用http://xxxx这样的URL格式,则被称为外部跳转。使用外部跳转的话,浏览着的浏览器中的URL地址会改变成新的地址,而使用内部跳转则浏览器中的地址不发生改变,看上去更像实际的二级域名虚拟服务器。

设置后重启Apache服务器就大功告成了!

 

例七、Rewrite 防盗链正则,不允许blog.csdn.net www.chinaz.com 这两个网站盗链 , 其它的网站都可以盗链.

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$ [NC]			# refere 不可为空,防止直接访问被跳转
RewriteCond %{HTTP_REFERER} csdn.net [NC,OR]	# 不区分大小写,匹配 csdn.net 或 chinaz.com
RewriteCond %{HTTP_REFERER} chinaz.com [NC]
RewriteRule .*\.(jpg|jpeg|gif|png|rar|zip|txt|ace|torrent|gz|swf)$ https://blog.mimvp.com/anti-link.png [R,NC,L]

 

 

Apache Rewrite 应用实例

米扑博客https://blog.mimvp.com

a) httpd.conf 

# blog.mimvp.com
<VirtualHost *:80>
    RewriteEngine on
    #RewriteRule   ^(.*)mimvp-proxy-lastest-free-proxy-ip  https://mimvp.com [L,R]
    RewriteRule   ^(.*)mimvp-proxy-lastest-free-proxy-ip  https://mimvp.com [R=permanent,L]
    RewriteRule   ^(.*)phpmyadmin  https://mimvp.com [R=permanent,L]
 
    ServerAdmin abc123@mimvp.com
    DocumentRoot /var/www/html/mimvp-blog
    ServerName blog.mimvp.com
 
    RewriteEngine on
    RewriteCond   %{HTTPS} !=on 
    RewriteRule   ^(.*)  https://%{SERVER_NAME}$1 [R=permanent,L]
 
    DirectoryIndex index.php 
    ErrorLog /var/log/blog.mimvp.com-error_log
    CustomLog /var/log/blog.mimvp.com-access_log customlog
</VirtualHost>
 
<VirtualHost *:443>
    RewriteEngine On
 
    ## 禁用已失效或不存在的网页路径
    RewriteRule   ^/html5  https://mimvp.com/$1 [R=permanent,L]
    RewriteRule   ^/phpmyadmin(.*)$  https://mimvp.com [R=permanent,L]
    RewriteRule   ^(.*)mimvp-proxy-lastest-free-proxy-ip  https://mimvp.com [R=permanent,L]
#    RewriteRule   ^/?p=([0-9]*)  /article/$1.html [R=permanent,L]    
 
    ## 禁用不常见的爬虫蜘蛛
    RewriteCond   %{HTTP_USER_AGENT} ^(.*)SemrushBot [NC,OR]
    RewriteCond   %{HTTP_USER_AGENT} ^(.*)AhrefsBot [NC,OR]
    RewriteCond   %{HTTP_USER_AGENT} ^(.*)DotBot [NC,OR]
    RewriteCond   %{HTTP_USER_AGENT} ^(.*)MJ12bot [NC]
    RewriteRule   ^(.*)$  https://mimvp.com/$1 [R=permanent,L]
 
    ## 防盗链
    RewriteCond %{HTTP_REFERER} !^$ [NC]
    RewriteCond %{HTTP_REFERER} !^(.*)mimvp [NC]
    RewriteCond %{HTTP_REFERER} !^(.*)mimvp.com [NC]
    RewriteCond %{HTTP_REFERER} !^(.*)baidu.com [NC]
    RewriteCond %{HTTP_REFERER} !^(.*)sogou.com [NC]
    RewriteCond %{HTTP_REFERER} !^(.*)so.com [NC]
    RewriteCond %{HTTP_REFERER} !^(.*)bing.com [NC]
    RewriteCond %{HTTP_REFERER} !^(.*)google.com [NC]
    RewriteRule .*\.(png|gif|jpg|jpeg|bmp|swf|pdf|txt|zip|rar)$ /anti-link.jpg [L,NC]
 
    SSLEngine on
    SSLCertificateChainFile /etc/httpd/conf/1_blog_root_bundle.crt
    SSLCertificateFile /etc/httpd/conf/2_blog.mimvp.com.crt
    SSLCertificateKeyFile /etc/httpd/conf/3_blog.mimvp.com.key
 
    ServerAdmin abc123@mimvp.com
    DocumentRoot /var/www/html/mimvp-blog
    ServerName blog.mimvp.com
 
    DirectoryIndex index.php index.html index.htm
    ErrorLog /var/log/blog.mimvp.com-error_log
    CustomLog /var/log/blog.mimvp.com-access_log customlog
</VirtualHost>

 

b).htaccess

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
 
# Redirect
Options +FollowSymLinks
RewriteCond %{HTTP_HOST}   !^(.*)mimvp\.com(.*)$ [NC]
RewriteRule ^(.*)$ https://blog.mimvp.com/$1 [R=301,L]
 
# Rewrite(blog)
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
 
 
<IfModule mod_expires.c> 
ExpiresActive On 
ExpiresDefault A600 
ExpiresByType image/x-icon A2592000 
ExpiresByType image/gif A2592000 
ExpiresByType image/jpeg A2592000 
ExpiresByType image/png A2592000 
ExpiresByType text/css A604800 
ExpiresByType text/plain A86400
ExpiresByType application/x-shockwave-flash A2592000
ExpiresByType application/x-javascript A604800 
ExpiresByType video/x-flv A2592000 
ExpiresByType application/pdf A2592000 
ExpiresByType text/html A600 
</IfModule> 
 
# END WordPress

RewriteCond 的用法:

“-d”(目录)
    将TestString视为一个路径名并测试它是否为一个存在的目录。
“-f”(常规文件)
    将TestString视为一个路径名并测试它是否为一个存在的常规文件。
“-s”(非空的常规文件)
    将TestString视为一个路径名并测试它是否为一个存在的、尺寸大于0的常规文件。
“-l”(符号连接)
    将TestString视为一个路径名并测试它是否为一个存在的符号连接。
“-x”(可执行)
    将TestString视为一个路径名并测试它是否为一个存在的、具有可执行权限的文件。该权限由操作系统检测。
“-F”(对子请求存在的文件)
    检查TestString是否为一个有效的文件,而且可以在服务器当前的访问控制配置下被访问。它使用一个内部子请求来做检查,由于会降低服务器的性能,所以请谨慎使用!
“-U”(对子请求存在的URL)
    检查TestString是否为一个有效的URL,而且可以在服务器当前的访问控制配置下被访问。它使用一个内部子请求来做检查,由于会降低服务器的性能,所以请谨慎使用!

图片重定向的示例:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^localhost$    // 如果域名是localhost
RewriteCond %{REQUEST_FILENAME} !-f     // 并且访问的文件找不到
RewriteRule ^images/(.+) http://127.0.0.1/test/showimages/$1 [R=302,L]     // 则跳转到另一个域名下的另一个目录访问这个图片

 

c)禁止访问 .htaccess 文件

conf/httpd.conf 配置文件里,默认是禁止访问 .ht 开头的文件

# The following lines prevent .htaccess and .htpasswd files from being 
# viewed by Web clients. 

<Files ".ht*">
   
Require all denied
</Files>

若想不出现 403 禁止状态,可以使用匹配重定向,如下

<Files ".ht*">
   
RedirectMatch 301  ^/.htaccess  https://blog.mimvp.com
</Files>

匹配 .htaccess 文件,重定向到米扑博客首页(https://blog.mimvp.com

 

 

参考推荐

Apache 设置禁止访问网站目录

Apache 封禁IP及IP段访问

实用 .htaccess 用法大全

.htaccess绑定域名到子目录

WordPress:.htaccess缓存提高网站性能

Apache 服务器负载低访问慢的原因分析和优化方案

Apache 工作的三种模式:Prefork、Worker、Event