Rewrite的Rewrite介绍

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Rewrite的Rewrite介绍相关的知识,希望对你有一定的参考价值。

参考技术A

很多情况下,某个 IP 的访问很容易造成 CPU 100% (比如 某些搜索引擎的固定抓取,别人大量的采集站点),这个时候我们就要利用一些有效的手段封掉对方的 IP,让他无法消耗服务器的资源,封 IP 的方法有很多种,如果你的 Web 服务器安装了 Rewrite 模块的话,也可以试试利用 Rewrite 规则封掉对方的 IP。
例如我们把某个特定的 IP 直接重定向到 baidu 首页,在网站根目录的 .htaccess 文件里添加代码:
Code:
RewriteCond % 123.123.123.123 [NC]
RewriteRule ^(.*)$ http://www.baidu.com/$1 [R=301]
将 123.123.123.123 这个 IP 替换成您要限制的 IP 即可。如果要实现多个 IP ,可以这样写:
RewriteCond % 123.123.123.123 [OR]
RewriteCond % 124.124.124.124 [NC]
RewriteRule ^(.*)$ http://www.baidu.com/$1 [R=301] Rewrite主要的功能就是实现URL的重写。它的正则表达式是基于Perl语言,入站的规则用于修改 HTTP 请求 Url。这些规则可以为以下几个目的,如演示对用户更加友好的 URL 命名空间为您的 Web 站点,将请求的 Url 重定向到新位置,或阻止访问 Url 来提供服务。出站的重写规则修改 HTTP 响应。例如,如果您的 Web 站点的导航结构已更改,您可以创建修改您的内容中的 Url,以便将 Web 页的内容指向正确的位置出站规则。然后,您可以创建基于缓存的位置与新的 url 的客户端请求重定向的入站的规则。可基于服务器级的(httpd.conf)和目录级的(.htaccess)两种方式。如果要想用到rewrite模块,必须先安装或加载rewrite模块。方法有两种一种是编译apache的时候就直接安装rewrite模块,别一种是编译apache时以DSO模式安装apache,然后再利用源码和apxs来安装rewrite模块。
基于服务器级的(httpd.conf)
有两种方法,一种是在httpd.conf的全局下直接利用RewriteEngine on来打开rewrite功能;另一种是在局部里利用RewriteEngine on来打开rewrite功能,下面将会举例说明,需要注意的是,必须在每个virtualhost里用RewriteEngine on来打开rewrite功能。否则virtualhost里没有RewriteEngine on它里面的规则也不会生效。
基于目录级的(.htaccess)
要注意一点那就是必须打开此目录的FollowSymLinks属性且在.htaccess里要声明RewriteEngine on。 一.我们通过在IIS中安装一个名为 ISAPI_Rewrite 的ISAPI筛选器来实现 Rewrite 功能,您需要做的事情只有一个,就是修改配置文件 httpd.ini ,有关该组件的详细使用方法,您可以登录该组件官方网站 http://www.somesite.com/ 来学习,这里我们举一个简单的例子来说明它的用法。
假设您要实现这样的 Rewrite 功能:您希望当用户访问 /about.htm (您的空间里可以并不需要存在 about.htm)的时候实际访问的是 /index.html
设置方法是:
1、创建一个文本文件,内容为
[ISAPI_Rewrite]
RewriteRule /about\\.htm /index\\.html
这里,RewriteRule 这一行即为规则行,这一行由三部分组成,三部分由空格隔开,第一部分即 RewriteRule 这几个字,第二部分为用户访问的地址(使用正则表达式),第三部分为实际存在于服务器上的文件路径。
2、将上述文件保存,命名为 httpd.ini 。
3、将这个文件上传到您的网站根目录中,对于我们的虚拟主机,即上传至 /web 文件夹中。
这时,当您访问 about.htm 的时候,看到的就是 index.html 的内容。
Rewrite 是一个功能强大的平台,要真正的使用它,您可能要花费相当长的时间来学习。如果您使用像 Discuz! 论坛等支持伪静态的系统,而仅仅是需要使用伪静态功能,那么您可以不必学习,直接复制论坛开发者提供的配置文件即可,但要注意配置文件必须命名为 httpd.ini ,并且这个文件必须放在网站的根目录下。
httpd.ini 修改或者上传后一般会立即生效,如果长时间不能生效,请登录主机控制面板将网站停止然后再启动。
评述:不建议修改http.conf文件,因为这样需要重新启动apache。建议在项目的根目录建立一个文档,文档名字就是.htaccess,然后把重写规则写进去,这样就不需要重启apache。
二、怎样借助 Rewrite 功能为特定的域名显示特定文件夹中的内容?
这实际上是 Rewrite 功能的巧用,因为我们既然可以将 /about.htm 重写为 /index.html ,我们也就可以把 /about.htm 重写为 /about/ 。下面我们讲具体的实现方法。
我们假设您有两个域名 www.name1.com 和 www.name2.com ,我们实现让访问 www.name1.com 时看到的是网站根下的内容,而访问 www.name2.com 时看到的是 /name2/ 文件夹中的内容。
那么设置步骤如下:
1、将您的网站捆绑域名 www.name1.com 和 www.name2.com ,这个非常重要,两个域名都要捆绑。这时候如果不做设置,两个域名访问的都是网站根下。
2、修改上述问题一中的 httpd.ini 文件,在尾部增加以下内容:
RewriteCond Host: www\\.name2\\.com
# 表示下一行规则只对 www.name2.com 生效(正则表达式中 \\. 表示 . 本身)。
RewriteRule ^(.*)$ /name2/$1 [I]
# 表示将所有网页 Rewrite 到 name2 文件夹中,[I]表示忽略大小写。
请确认上述内容位于 [ISAPI_Rewrite] 行之下,如果原本网站不存在 httpd.ini 文件,请将上述内容前面加上 [ISAPI_Rewrite] 。
3、将修改后的 httpd.ini 上传到网站根下覆盖原文件。
通过这个方法,您可以将捆绑在网站上的任何一个域名采用任何特定的 Rewirte 规则,实现类似捆绑子目录的功能当然也是不在话下。这样,您的空间能捆绑多少个域名,您就可以建立多少个内容不同的网站了。 ngx_http_rewrite_module模块允许正则替换URI,返回页面重定向,和按条件选择配置。
ngx_http_rewrite_module模块指令按以下顺序处理: 处理在server级别中定义的模块指令; 为请求查找location; 处理在选中的location中定义的模块指令。如果指令改变了URI,按新的URI查找location。这个循环至多重复10次,之后nginx返回错误500 (Internal Server Error)。 指令 语法:break;  默认值:—上下文:server,location,if  停止处理当前这一轮的ngx_http_rewrite_module指令集。
举例:
if ($slow) limit_rate 10k; break; 语法:if(condition) ...   默认值:—上下文:server,location  计算指定的condition的值。如果为真,执行定义在大括号中的rewrite模块指令,并将if指令中的配置指定给请求。if指令会从上一层配置中继承配置。
条件可以是下列任意一种: 变量名;如果变量值为空或者是以“0”开始的字符串,则条件为假; 使用“=”和“!=”运算符比较变量和字符串; 使用“~”(大小写敏感)和“~*”(大小写不敏感)运算符匹配变量和正则表达式。正则表达式可以包含匹配组,匹配结果后续可以使用变量$1..$9引用。如果正则表达式中包含字符“”或者“;”,整个表达式应该被包含在单引号或双引号的引用中。 使用“-f”和“!-f”运算符检查文件是否存在; 使用“-d”和“!-d”运算符检查目录是否存在; 使用“-e”和“!-e”运算符检查文件、目录或符号链接是否存在; 使用“-x”和“!-x”运算符检查可执行文件; 举例:
if ($http_user_agent ~ MSIE) rewrite ^(.*)$ /msie/$1 break;if ($http_cookie ~* id=([^;]+)(?:;|$)) set $id $1;if ($request_method = POST) return 405;if ($slow) limit_rate 10k;if ($invalid_referer) return 403;
内嵌变量$invalid_referer的值是通过valid_referers指令设置的。 语法:returncode[text];  returncodeURL;  returnURL;  默认值:—上下文:server,location,if  停止处理并返回指定code给客户端。返回非标准的状态码444可以直接关闭连接而不返回响应头。
从0.8.42版开始,可以在指令中指定重定向的URL(状态码为301、302、303和307),或者指定响应体文本(状态码为其它值)。响应体文本或重定向URL中可以包含变量。作为一种特殊情况,重定向URL可以简化为当前server的本地URI,那么完整的重定向URL将按照请求协议($scheme)、server_name_in_redirect指令和port_in_redirect指令的配置进行补全。
另外,状态码为302的临时重定向使用的URL可以作为指令的唯一参数。该参数应该以“http://”、“https://”或者“https://”开始。URL中可以包含变量。
0.7.51版本以前只能返回下面状态码: 204、400、402— 406、408、410、411、413、416 和 500— 504。
直到1.1.16和1.0.13版,状态码307才被认为是一种重定向。 语法:rewriteregexreplacement[flag];  默认值:—上下文:server,location,if  如果指定的正则表达式能匹配URI,此URI将被replacement参数定义的字符串改写。rewrite指令按其在配置文件中出现的顺序执行。flag可以终止后续指令的执行。如果replacement的字符串以“http://”或“https://”开头,nginx将结束执行过程,并返回给客户端一个重定向。
可选的flag参数可以是其中之一: last 停止执行当前这一轮的ngx_http_rewrite_module指令集,然后查找匹配改变后URI的新location; break 停止执行当前这一轮的ngx_http_rewrite_module指令集; redirect 在replacement字符串未以“http://”或“https://”开头时,使用返回状态码为302的临时重定向; permanent 返回状态码为301的永久重定向。 完整的重定向URL将按照请求协议($scheme)、server_name_in_redirect指令和port_in_redirect指令的配置进行补全。
举例:
server ... rewrite ^(/download/.*)/media/(.*)\\..*$ $1/mp3/$2.mp3 last; rewrite ^(/download/.*)/audio/(.*)\\..*$ $1/mp3/$2.ra last; return 403; ...
但是当上述指令写在“/download/”的location中时,应使用标志break代替last,否则nginx会重复10轮循环,然后返回错误500:
location /download/ rewrite ^(/download/.*)/media/(.*)\\..*$ $1/mp3/$2.mp3 break; rewrite ^(/download/.*)/audio/(.*)\\..*$ $1/mp3/$2.ra break; return 403;
如果replacement字符串包括新的请求参数,以往的请求参数会添加到新参数后面。如果不希望这样,在replacement字符串末尾加一个问号“?”,就可以避免,比如:
rewrite ^/users/(.*)$ /show?user=$1? last;
如果正则表达式中包含字符“”或者“;”,整个表达式应该被包含在单引号或双引号的引用中。 语法:rewrite_logon|off;  默认值:rewrite_log off;上下文:http,server,location,if  开启或者关闭将ngx_http_rewrite_module模块指令的处理日志以notice级别记录到错误日志中。 语法:setvariablevalue;  默认值:—上下文:server,location,if  为指定变量variable设置变量值value。value可以包含文本、变量或者它们的组合。 语法:uninitialized_variable_warnon|off;  默认值:uninitialized_variable_warn on;上下文:http,server,location,if  控制是否记录变量未初始化的警告到日志。
内部实现
ngx_http_rewrite_module模块的指令在解析配置阶段被编译成nginx内部指令。这些内部指令在处理请求时被解释执行。而解释器是一个简单的堆栈机器。
比如,下面指令
location /download/ if ($forbidden) return 403; if ($slow) limit_rate 10k; rewrite ^/(download/.*)/media/(.*)\\..*$ /$1/mp3/$2.mp3 break;
将被翻译成下面这些指令:
variable $forbiddencheck against zero return 403 end of codevariable $slowcheck against zeromatch of regular expressioncopy /copy $1copy /mp3/copy $2copy .mp3end of regular expressionend of code
请注意没有对应上面的limit_rate指令的内部指令,因为这个指令与ngx_http_rewrite_module模块无关。nginx会为这个if块单独创建一个配置,包含limit_rate等于10k。如果条件为真,nginx将把这个配置指派给请求。
指令
rewrite ^/(download/.*)/media/(.*)\\..*$ /$1/mp3/$2.mp3 break;
可以通过将正则表达式中的第一个斜线“/”放入圆括号,来实现节约一个内部指令:
rewrite ^(/download/.*)/media/(.*)\\..*$ $1/mp3/$2.mp3 break;
对应的内部指令将会是这样:
match of regular expressioncopy $1copy /mp3/copy $2copy .mp3end of regular expressionend of code

location和rewrite介绍

location

从功能看 rewrite 和 location 似乎有点像,都能实现跳转,主要区别在于 rewrite 是在同一域名内更改获取资源的路径,而 location 是对一类路径做控制访问或反向代理,还可以proxy_pass 到其他机器。

location 大致可以分为三类:

精准匹配location = / { }
一般匹配location / { }
正则匹配location ~ / { }

location 常用的匹配规则:

= :进行普通字符精确匹配,也就是完全匹配。
^~ :表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其它 location。
~ :区分大小写的匹配。
~* :不区分大小写的匹配。
!~ :区分大小写的匹配取非。
!~* :不区分大小写的匹配取非。

location 优先级:

首先精确匹配 =
其次前缀匹配 ^~
其次是按文件中顺序的正则匹配 ~ 或 ~*
然后匹配不带任何修饰的前缀匹配
最后是交给 / 通用匹配

优先级总结:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ,* 正则顺序) > (location 部分起始路径) > (location /)

实际网站使用中,至少有三个匹配规则定义:
第一个必选规则
直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,比如说官网。
这里是直接转发给后端应用服务器了,也可以是一个静态首页
location = / {
proxy_pass http://tomcat_server/;
}

第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
root /webroot/static/;
}

location ~* .(html|gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}

第三个规则就是通用规则,比如用来转发带.php、.jsp后缀的动态请求到后端应用服务器
非静态文件请求就默认是动态请求
location / {
proxy_pass http://tomcat_server;
}

常用的Nginx 正则表达式

^匹配输入字符串的起始位置
$匹配输入字符串的结束位置
*匹配前面的字符零次或多次
+匹配前面的字符一次或多次
?匹配前面的字符零次或一次
.匹配除“\\n”之外的任何单个字符
\\将后面接着的字符标记为一个特殊字符或一个原义字符或一个向后引用
\\d匹配纯数字
{ n }重复 n 次
{ n, }重复 n 次或更多次
{n,m}重复 n 到 m 次
[ ]定义匹配的字符范围
[a-z]匹配 a-z 小写字母的任意一个
[a-zA-Z0-9]匹配所有大小写字母或数字
( )表达式的开始和结束位置

rewrite

rewrite功能就是,使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。
rewrite只能放在server{ },location{ },if{ }中,并且默认只能对域名后边的除去传递的参数外的字符串起作用.

rewrite 执行顺序如下:

(1) 执行 server 块里面的 rewrite 指令。
(2) 执行 location 匹配。
(3) 执行选定的 location 中的 rewrite 指令。

语法rewrite regex replacement flag
regex :表示正则匹配规则。
replacement :表示跳转后的内容。
flag :表示 rewrite 支持的 flag 标记。

flag标记说明

last本条规则匹配完成后,继续向下匹配新的location URI规则,一般用在 server 和 if 中。
break本条规则匹配完成即终止,不再匹配后面的任何规则,一般使用在 location 中
redirect返回302临时重定向,浏览器地址会显示跳转后的URL地址
permanent返回301永久重定向,浏览器地址栏会显示跳转后的URL地址。

rewrite 示例

1.基于域名的跳转
现在公司旧域名www.kgc.com有业务需求变更,需要使用新域名www.benet.com代替,但是旧域名不能废除,需要跳转到新域名上,而且后面的参数保持不变。

vim /usr/local/nginx/conf/nginx.conf
server {
	listen       80;
	server_name  www.kgc.com;		#域名修改	
	charset utf-8;
	access_log  /var/log/nginx/www.kgc.com-access.log  main; #日志修改
	location / {                                          #添加域名重定向
        if ($host = 'www.kgc.com'){#$host为rewrite全局变量,代表请求主机头字段或主机名
     rewrite ^/(.*)$ http://www.benet.com/$1 permanent;	#$1为正则匹配的内容,即域名后边的字符串	                                    
        }
        root   html;
        index  index.html index.htm;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.基于客户端 IP 访问跳转
今天公司业务新版本上线,要求所有 IP 访问任何内容都显示一个固定维护页面,只有公司 IP :192.168.80.10访问正常。

server {
	listen       80;
	server_name  www.kgc.com;		#域名修改	
	charset utf-8;
	access_log  /var/log/nginx/www.kgc.com-access.log  main;	#日志修改

	#设置是否合法的IP标记
      set $rewrite true;			#设置变量$rewrite,变量值为boole值true
    #判断是否为合法IP
	if ($remote_addr = "192.168.80.10"){		#当客户端IP为192.168.80.10时,将变量值设为false,不进行重写
        set $rewrite false;
    }
	#除了合法IP,其它都是非法IP,进行重写跳转维护页面
    if ($rewrite = true){						#当变量值为true时,进行重写
        rewrite (.+) /weihu.html;				#重写在访问IP后边插入/weihu.html,例如192.168.80.11/weihu.html
    }
    location = /weihu.html {
        root /var/www/html;	#网页返回/var/www/html/weihu.html的内容
    }
	
	location / {
        root   html;
        index  index.html index.htm;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.基于旧域名跳转到新域名后面加目录
现在访问的是 http://bbs.kgc.com,现在需要将这个域名下面的访问都跳转到http://www.kgc.com/bbs

server {
	listen       80;
	server_name  bbs.kgc.com;		#域名修改	
	charset utf-8;
	access_log  /var/log/nginx/www.kgc.com-access.log  main;
	#添加
	location /post {
        rewrite (.+) http://www.kgc.com/bbs$1 permanent;        #这里的$1为位置变量,代表/post
    }
	
	location / {
        root   html;
        index  index.html index.htm;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
4.基于参数匹配的跳转
现在访问http://www.kgc.com/100-(100|200)-100.html 跳转到http://www.kgc.com页面。

server {
	listen       80;
	server_name  www.kgc.com;		#域名修改	
	charset utf-8;
	access_log  /var/log/nginx/www.kgc.com-access.log  main;
	
	if ($request_uri ~ ^/100-(100|200)-(\\d+).html$) {
        rewrite (.*) http://www.kgc.com permanent;
    }

	location / {
        root   html;
        index  index.html index.htm;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5. 基于目录下所有 php 结尾的文件跳转

server {
	listen       80;
	server_name  www.kgc.com;		#域名修改	
	charset utf-8;
	access_log  /var/log/nginx/www.kgc.com-access.log
	
	location ~* /upload/.*\\.php$ {
        rewrite (.+) http://www.kgc.com permanent;
    }

	location / {
        root   html;
        index  index.html index.htm;
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以上是关于Rewrite的Rewrite介绍的主要内容,如果未能解决你的问题,请参考以下文章

Nginx ——Rewrite 语法介绍

Fluentd插件rewrite-tag-filter介绍

Nginx rewrite配置

Nginx配置rewrite过程介绍

Apache 的 Rewrite 规则详细介绍

nginx rewrite uri地址重写