Apache Rewrite 规则 RewriteCond、RewriteRule 参数配置详解
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 应用实例
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 工作的三种模式:Prefork、Worker、Event
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2018-12-30 05:23:58
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!
转载注明: Apache Rewrite 规则 RewriteCond、RewriteRule 参数配置详解 (米扑博客)