Nginx的Rewrite详解(七)

背景

         这一章我们来一起聊聊Nginx的Rewrite的功能,Rewrite用于对请求的URL进行重写,然后返回重定向或有条件地选择配置上。后续我们需要了解的Nginx的HTTPS的功能也是基于Rewrite之上的。接下来我们展开说说吧。

 Rewrite详解

 1.    什么是Rewrite?

        Rewrite主要实现URL地址的重写,以及URL地址的跳转;即:就是将用户请求web服务器的URL地址重新修改为其他URL地址的过程。

2.     Rewrite的应用场景

2.1    地址跳转:比如当用户访问的xhz.com/edu这个URL时,将其重定向到一个新的域名edu.xhz.com。

2.2    协议跳转:当用户通过http的请求协议重新跳转至https协议(实现https的主要手段)。

2.3    URL静态化:将动态URL地址显示为静态URL的一种技术,能提高搜索引擎的抓取,并能减少动态URL对外暴露过多的参数。(Rewrite会轻微增加服务器的负担)。

3.     如何实现?

         通过ngx_http_rewrite_module模块支持url重写、支持if条件判断,但不支持else。另外该模块需要PCRE支持,应在编译nginx时指定PCRE支持。根据相关变量重定向和选择不同的配置,从一个location跳转到另一个location,不过这样的循环最多可以执行10次,超过后nginx将返回500错误。同时,重写模块包含set指令,来创建新的变量并设其值,如记录条件标识、传递参数到其他location、记录做了什么等等。

ngx_http_rewrite_module官网:https://nginx.org/en/docs/http/ngx_http_rewrite_module.html

 4.     Rewrite参数

4.1      break

         只执行break所在的指令,停止执行break后续的所有指令。

### 语法
Syntax:	break;
Default:	—
Context:	server, location, if


###  示例
if ($slow) {
    limit_rate 10k;
    break;
}

 4.2     if 

         对给定的条件(condition)进行判断,如果条件为真,大括号内的rewrite指令将被执行。

Syntax:	if (condition) { ... }
Default:	—
Context:	server, location

 condition条件可以满足如下:

***当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false;

1. 使用“=”和“!=”比较一个变量和字符串;

2. 使用“~”做正则表达式匹配,“~*”做不区分大小写的正则匹配,“!~”做区分大小写的正则不匹配;

3. 使用“-f”和“!-f” 检查一个文件是否存在;

4. 使用“-d”和“!-d”检查一个目录是否存在;

5. 使用“-e”和“!-e”检查一个文件、目录、符号链接是否存在;

6. 使用“-x”和“ !-x”检查一个文件是否可执行;

示例:

// 当请求头中的User-Agent中包含MSIE(~区分大小写)时rewrite请求到/msie/$1目录下,$1表示匹配的URI
if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
}


// 当请求头中的cookie匹配正则的时候,将设置变量$id 为$1  其中$1= =([^;]+)(?:;|$)匹配到的内容
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
}

//  当请求头中的请求类型method是POST的时,直接返回405
if ($request_method = POST) {
    return 405;
}


//如果$slow可以通过set指令设置,则进行限速处理
if ($slow) {
    limit_rate 10k;
}

//  如果为真,则返回403
if ($invalid_referer) {
    return 403;
}

//如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查
if (!-f $request_filename){
    break;
    proxy_pass http://127.0.0.1;
}
 
//如果请求头中包含"post=140",则重定向到example.com
if ($args ~ post=140){
    rewrite ^ http://example.com/ permanent;
}
 

上诉示例来自nginx的官网,可以发现在匹配的过程中主要还是正则表达式,在来回顾下正则。

=	精准匹配 	
^~	以某个字符串开头	
~	区分大小写的正则匹配	
/	通用匹配,任何请求都会匹配到	
~*	不区分大小写的正则匹配	


.     :匹配除换行符以外的任意字符
?     :重复0次或1次
+     :重复1次或更多次
*     :重复0次或更多次
\d    :匹配数字
^     :匹配字符串的开始字符
$     :匹配字符串的结束字符
{n}   :重复n次
{n,}  :重复n次或更多次
[c]   :匹配单个字符c
[a-z] :匹配a-z小写字母的任意一个

4.3     return

         停止处理并为客户端返回状态码,非标准的444状态码将关闭连接,不发送任何响应头。可以使用的状态码有:204,400,402-406,408,410, 411, 413, 416与500-504。如果状态码附带文字段落,该文本将被放置在响应主体。相反,如果状态码后面是一个URL,该URL将成为location头部值。没有状态码的URL将被视为一个302状态码。此外,可以将带有代码 302 的临时重定向 URL 指定为唯一参数。此类参数应以“http://”、“https://”或“$scheme”字符串开头。 URL 可以包含变量。

Syntax:	return code [text];
        return code URL;
        return URL;
Default:	—
Context:	server, location, if

4.4     rewrite

        如果指定的正则表达式与请求 URI 匹配,则 URI 将按照替换字符串中的指定进行更改。重写指令按照它们在配置文件中出现的顺序依次执行。可以使用标志终止对指令的进一步处理。如果替换字符串以“http://”、“https://”或“$scheme”开头,则处理停止并将重定向返回给客户端。

Syntax:	rewrite regex replacement [flag];
Default:	—
Context:	server, location, if


regex :  正则表达

replacement :  重定向的内容


[flag]: 标志位,包含:last,break,redirect,permanent

       regex和replacement没什么具体可说的,后续我们通过示例进行理解就行,主要是flag的参数是什么含义,我们需要了解下。我们先看个示例吧!

//当通过www.xhz_rewrite.com/1.html访问时,此时通过rewrite返回的结果为b.html中的内容。
server {
    listen 80;
    server_name xhz_rewrite.com www.xhz_rewrite.com;
    root /rewrite;

    location / {
        rewrite  /1.html /2.html;
        rewrite  /2.html /3.html;
    }

    location /2.html {
        rewrite /2.html /a.html;
    }

    location /3.html {
        rewrite /3.html /b.html;
    }
}

//当通过www.xhz_rewrite.com/1.html访问时,此时通过rewrite返回的结果为2.html中的内容。
server {
    listen 80;
    server_name xhz_rewrite.com www.xhz_rewrite.com;
    root /rewrite;

    location / {
        rewrite  /1.html /2.html break;
        rewrite  /2.html /3.html;
    }

    location /2.html {
        rewrite /2.html /a.html;
    }

    location /3.html {
        rewrite /3.html /b.html;
    }
}


//当通过www.xhz_rewrite.com/1.html访问时,此时通过rewrite返回的结果为a.html中的内容。
server {
    listen 80;
    server_name xhz_rewrite.com www.xhz_rewrite.com;
    root /rewrite;

    location / {
        rewrite  /1.html /2.html last;
        rewrite  /2.html /3.html;
    }

    location /2.html {
        rewrite /2.html /a.html;
    }

    location /3.html {
        rewrite /3.html /b.html;
    }
}

总结:

break:完成该rewrite规则的执行后遇到break就会终止后所有指令的执行。

last:完成该rewrite规则的执行后遇到last,就会将重写后的URI,重server开头开始匹配,匹配到哪个就执行哪个。

//通过 www.xhz_rewrite.com/1.html访问,放回的结果是3.htnl的内容,返回的转态码为301
server {
    listen 80;
    server_name xhz_rewrite.com www.xhz_rewrite.com;
    root /rewrite;

    location / {
        rewrite  /1.html /2.html permanent;
        rewrite  /2.html /3.html;
    }
}


//通过 www.xhz_rewrite.com/1.html访问,放回的结果是3.htnl的内容,返回的转态码为302
server {
    listen 80;
    server_name xhz_rewrite.com www.xhz_rewrite.com;
    root /rewrite;

    location / {
        rewrite  /1.html /2.html redirect;
        rewrite  /2.html /3.html;
    }
}

总结:

redirect:返回302临时重定向,地址栏会显示跳转后的地址;

permanent:返回301永久重定向,地址栏会显示跳转后的地址;即表示如果客户端不清理浏览器缓存,那么返回的结果将永久保存在客户端浏览器中了。因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return

Rewrite实例

 1.    根据浏览器的语言不同调度到不同的页面中。

server {
    listen 80;
    server_name xhz_chinese.com www.xhz_chinese.com;
    root /rewrite;



    location / {
        if ($http_accept_language ~* "zh-CN|zh") {
            set $language zh;
    }
        if ($http_accept_language ~* "en") {
            set $language en;
    }
        rewrite ^/$ /$language;
    }
}

2.     通过手机访问xhz.iphone.com跳转到xhz.iphone.com/test

server {
    listen 80;
    server_name xhz_iphone.com www.xhz_iphone.com;
    root /rewrite/iphone;

    location / {
        if ($http_user_agent ~* "iphone|android|ipad") {
            rewrite ^/$ /test;
        }
        
    }
}

3.     通过收集手机xhz.test.com跳转到edu.xhz.test.com

server {
    listen 80;
    server_name xhz123.com www.xhz123.com;
    root /rewrite/xhz123;

    location / {
        index index.html;
        if ($http_user_agent ~* "iphone|android|ipad") {
            rewrite ^/$ http://edu_xhz_iphone.com;
        }
        
    }
}

4.     通过http协议请求,自动跳转到https协议。

server {
    listen 80;
    server_name xhz_https.com www.xhz_https.com;
    root /rewrite/https;

    location ^(.*)$ {
        rewrite ^(.*)$ https://$server_name$1 redirect;
    }
    

}

server {
    listen 443 default;
    server_name xhz_https.com www.xhz_https.com;
}

 5.     网站维护过程中,希望用户访问所有网站都重定向到一个维护页面。

server {
    listen 80;
    server_name xhz_wh.com www.xhz_wh.com;
    root /rewrite/wh;

    rewrite ^(.*)$ /wh.html break;

    location / {
        index index.html;
    }
}

6.   单服务器遇到403 404 502等错误时,自动跳转到临时维护的静态页面。

server {
    listen 80;
    server_name xhz_static.com www.xhz_static.com;
    root /rewrite/static;


    location / {
        index index.html;
    }
    error_page 404 403 502 = @err_html
    location @err_html {
        rewrite ^(.*)$ /static.html break;
    }

}

7.     公司网站在停机维护时,指定ip能正常访问,其他ip跳转到维护页面。

server {
    listen 80;
    server_name bind_ip.com www.bind_ip.com;
    root /rewrite/bind_ip;

    set $ip 0;
    if ($remote_addr = '192.168.65.2|192.168.65.3') {
        set $ip 1;
    }

    if ($ip = '0') {
        rewrite ^(.*)$ /bind_ip.html break;
    }

    ## 如果想针对耨个location进行操作,则将如上配置写入location中即可

    location / {
        index index.html;
    }

}

8.    公司网站后台/admin,只允许公司的出口公网ip可以访问,其他ip访问全部返回500

server {
    listen 80;
    server_name admin.com www.admin.com;
    root /rewrite/;

    location /admin {
        set $ip 0;
        if ($remote_addr = ' 113.57.152.160| 113.57.152.161') {
            set $ip 1;
        }

        if ($ip = '0') {
            return 500;
        }
        index index.html;
    }

}

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小肖同学..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值