1 Nginx重写简介

Nginx重写功能(Rewrite)由ngx_http_rewrite_module模块提供,可使用正则表达式改变请求的URI,返回重定向地址或内容,并可以根据条件选择适当的配置。

1.1 Rewrite指令格式
重写指令格式如下:

# 关键字 正则表达式 代替的内容 重写类型
rewrite regex replacement [flag]

1.2 重写类型
Nginx重写类型 [flag] 有last、break、redirect和permanent四种,如下:

last:本条重写规则匹配完成后,终止匹配后续重写规则,并重新发起请求继续匹配新的location URI规则;浏览器地址栏URL地址不变
break:本条重写规则匹配完成后,终止匹配后续重写规则; 浏览器地址栏URL地址不变
redirect:返回302临时重定向,浏览器地址会显示重写后的URL地址
permanent:返回301永久重定向,浏览器地址会显示重写后的URL地址
1.3 重写配置
为了演示四种重写类型的不同,在nginx的配置中添加/last、/break、/redirect、/permanent、/rewrite五个路由地址,完整配置如下:

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    root   /usr/share/www/site1;
    location / {
        index  index.html index.htm;
    }

    # 请求重定向测试
    location /rewrite {
        add_header Content-Type 'text/html; charset=utf-8';
        return 200 'message in rewrite';
    }

    # last
    location /last {
        add_header Content-Type 'text/html; charset=utf-8';
        rewrite ^/last /rewrite last;
    }

    # break
    location /break {
        add_header Content-Type 'text/html; charset=utf-8';
        rewrite ^/break /rewrite break;
        # rewrite ^/break http://www.crane.run break;
    }

    # 临时重定向
    location /redirect {
        add_header Content-Type 'text/html; charset=utf-8';
        rewrite ^ http://www.crane.run redirect;
    }
    # 永久重定向
    location /permanent {
        add_header Content-Type 'text/html; charset=utf-8';
        rewrite ^ http://www.crane.run permanent;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

2.例子

server {

    location /break/ {
        rewrite ^/break/(.*) /test/$1 break;
        echo "break page";
    }

    location /last/ {
         rewrite ^/last/(.*) /test/$1 last;
         echo "last page";
    }    

    location /test/ {
       echo "test page";
    }
}

请求:http://dcshi.com/break/***
输出: break page
分析:正如上面讨论所说,break是跳过当前请求的rewrite阶段,并继续执行本请求的其他阶段,很明显,对于/foo 对应的content阶段的输出为 echo “break page”; (content阶段,可以简单理解为产生数据输出的阶段,如返回静态页面内容也是在content阶段;echo指令也是运行在content阶段,一般情况下content阶段只能对应一个输出指令,如同一个location配置两个echo,最终只会有一个echo指令被执行);当然如果你把/break/里的echo 指令注释,然后再次访问/break/xx会报404,这也跟我们预期一样:虽然/break/xx被重定向到/test/xx,但是break指令不会重新开启一个新的请求继续匹配,所以nginx是不会匹配到下面的/test/这个location;在echo指令被注释的情况下,/break/ 这location里只能执行nginx默认的content指令,即尝试找/test/xx这个html页面并输出起内容,事实上,这个页面不存在,所以会报404的错误。

请求: http://dcshi.com/last/***
输出: test page
分析: last与break最大的不同是,last会重新发起一个新请求,并重新匹配location,所以对于/last,重新匹配请求以后会匹配到/test/,所以最终对应的content阶段的输出是test page;

3 总结
通过上面的验证,结合官方文档,可见几种重写的区别:

break与last都停止处理后续重写规则,只不过last会重新发起新的请求并使用新的请求路由匹配location,但break不会。所以当请求break时,如匹配成功,则请求成功,返回200;如果匹配失败,则返回404。
服务器配置好redirect和permanent之后,打开浏览器分别访问这两个请求地址,然后停止Nginx服务。这时再访问redirect请求会直接报出无法连接的错误。但是permanent请求是永久重定向,浏览器会忽略原始地址直接访问永久重定向之后的地址,所以请求仍然成功。(这个验证不能禁用浏览器的缓存,否则即使是permanent重定向,浏览器仍然会向原始地址发出请求验证之前的永久重定向是否有效)
对于搜索引擎来说,搜索引擎在抓取到301永久重定向请求响应内容的同时也会将原始的网址替换为重定向之后的网址,而对于302临时重定向请求则仍然会使用原始的网址并且可能会被搜索引擎认为有作弊的嫌疑。所以对于线上正式环境来讲,尽量避免使用302跳转
如果replacement以”http://”或”https://”或“$scheme”开始,处理过程将终止,并将这个重定向直接返回给客户端。