Nginx重定向

小明 2025-05-05 16:10:50 5

Rewrite简介


���多博客内容访问只爱吃火龙果,点击了解详情


Rewrite是Nginx服务器提供的一个重要基本功能,是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写。

注意:Nginx服务器的Rewrite功能的实现依赖于PCRE的支持,因此在编译安装Nginx服务器之前,需要安装PCRE库。Nginx使用的是ngx_http_rewrite_module模块来解析和处理Rewrite功能的相关配置。

  • “地址重写"与"地址转发”

    重写和转发的区别:

    1. 地址重写浏览器地址会发生变化而地址转发则不变
    2. 一次地址重写会产生两次请求而一次地址转发只会产生一次请求
    3. 地址重写到的页面必须是一个完整的路径而地址转发则不需要
    4. 地址重写因为是两次请求所以request范围内属性不能传递给新页面,地址转发因为是一次请求所以可以传递值
    5. 地址转发速度快于地址重写

    Rewrite规则

    Rewrite常用全局变量

    变量说明案例
    $args变量中存放了请求URL中的请求指令。
    功能和$query_string一样http://172.41.100.15:8088/args?a=1&b=3
    $args=a=1&b=3
    $http_user_agent变量存储的是用户访问服务的代理信息
    (如果通过浏览器访问,记录的是浏览器的相关版本信息)http_user_agent = Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
    $host变量存储的是访问服务器的server_name值host =172.41.100.15
    $document_uri变量存储的是当前访问地址的URI。document_uri =/args
    $document_root变量存储的是当前请求对应location的root值,如果未设置,默认指向Nginx自带html目录所在位置document_root=/home/nginx/html
    $content_length变量存储的是请求头中的Content-Length的值
    $content_type变量存储的是请求头中的Content-Type的值
    $http_cookie变量存储的是客户端的cookie信息,可以通过add_header Set-Cookie 'cookieName=cookieValue’来添加cookie数据
    $limit_rate变量中存储的是Nginx服务器对网络连接速率的限制,也就是Nginx配置中对limit_rate指令设置的值,默认是0,不限制。
    $remote_addr变量中存储的是客户端的IP地址remote_addr=172.41.100.13
    $remote_port变量中存储了客户端与服务端建立连接的端口号remote_port=50360
    $remote_user变量中存储了客户端的用户名,需要有认证模块才能获取
    $scheme变量中存储了访问协议scheme =http
    $server_addr变量中存储了服务端的地址server_addr=172.41.100.15
    $server_name变量中存储了客户端请求到达的服务器的名称server_name=localhost
    $server_port变量中存储了客户端请求到达服务器的端口号server_port=8088
    $server_protocol变量中存储了客户端请求协议的版本,比如"HTTP/1.1"server_protocol=HTTP/1.1
    $request_body_file变量中存储了发给后端服务器的本地文件资源的名称
    $request_method变量中存储了客户端的请求方式,比如"GET","POST"等request_method =GET
    $request_filename变量中存储了当前请求的资源文件的路径名request_filename =/home/nginx/html/args
    $request_uri变量中存储了当前请求的URI,并且携带请求参数request_uri=/args?a=1&b=3

    set指令

    该指令用来设置一个新的变量。

    语法set $variable value;
    默认值
    位置server、location、if

    variable:变量的名称,变量名称要用"$"作为变量的第一个字符,且不能与Nginx服务器预设的全局变量同名。

    value:变量的值,可以是字符串、其他变量或者变量的组合等。

    if指令

    该指令用来支持条件判断,并根据条件判断结果选择不同的Nginx配置。

    语法if (condition){…}
    默认值
    位置server、location

    condition为判定条件,可以支持以下写法:

    1. 变量名。如果变量名对应的值为空或者是0,if都判断为false,其他条件为true。
    if ($param){
        
    }
    
    1. 使用"=“和”!="比较变量和字符串是否相等,满足条件为true,不满足为false
    if ($request_method = POST){
        return 405;
    }
    

    注意:此处和Java不太一样的地方是字符串不需要添加引号。

    1. 使用正则表达式对变量进行匹配,匹配成功返回true,否则返回false。变量与正则表达式之间使用"“、”“、”!“、”!"来连接
      1. "~"代表匹配正则表达式过程中区分大小写
      2. "~*"代表匹配正则表达式过程中不区分大小写
      3. "!“和”!*"刚好和上面取相反值,如果匹配上返回false,匹配不上返回true
    if ($http_user_agent ~ MSIE){
    	#$http_user_agent的值中是否包含MSIE字符串,如果包含返回true
    }
    

    注意:正则表达式字符串一般不需要加引号,但是如果字符串中包含"}“或者是”;"等字符时,就需要把引号加上。

    1. 判断请求的文件是否存在使用"-f"和"!-f",

      当使用"-f"时,如果请求的文件存在返回true,不存在返回false。

      当使用"!-f"时,如果请求文件不存在,但该文件所在目录存在返回true,文件和目录都不存在返回false,如果文件存在返回false

    if (-f $request_filename){
    	#判断请求的文件是否存在
    }
    if (!-f $request_filename){
    	#判断请求的文件是否不存在
    }
    
    1. 判断请求的目录是否存在使用"-d"和"!-d",

      当使用"-d"时,如果请求的目录存在,if返回true,如果目录不存在则返回false

      当使用"!-d"时,如果请求的目录不存在但该目录的上级目录存在则返回true,该目录和它上级目录都不存在则返回false,如果请求目录存在也返回false.

    2. 判断请求的目录或者文件是否存在使用"-e"和"!-e"

      当使用"-e",如果请求的目录或者文件存在时,if返回true,否则返回false.

      当使用"!-e",如果请求的文件和文件所在路径上的目录都不存在返回true,否则返回false

    3. 判断请求的文件是否可执行使用"-x"和"!-x"

      当使用"-x",如果请求的文件可执行,if返回true,否则返回false

      当使用"!-x",如果请求文件不可执行,返回true,否则返回false

    break指令

    用于中断当前相同作用域中的其他Nginx配置。与该指令处于同一作用域的Nginx配置中,位于它前面的指令配置生效,位于后面的指令配置无效。

    语法break;
    默认值
    位置server、location、if
    location /{
    	if ($param){
    		set $id ;
    		break;
        #不生效,限制nginx向客户端每秒传输速率
    		limit_rate 10k;
    	}
    }
    

    return指令

    用于完成对请求的处理,直接向客户端返回响应状态代码。在return后的所有Nginx配置都是无效的。

    语法return code [text]; return code URL; return URL;
    默认值
    位置server、location、if
    • code:为返回给客户端的HTTP状态代理。可以返回的状态代码为0~999的任意HTTP状态代理
    • text:为返回给客户端的响应体内容,支持变量的使用
    • URL:为返回给客户端的URL地址

      rewrite指令

      该指令通过正则表达式的使用来改变URI。可以同时存在一个或者多个指令,按照顺序依次对URL进行匹配和处理。

      语法rewrite regex replacement [flag];
      默认值
      位置server、location、if

      regex:用来匹配URI的正则表达式

      replacement:匹配成功后,用于替换URI中被截取内容的字符串。

      如果该字符串是以"http://"或者"https://"开头的,则不会继续向下对URI进行其他处理,而是直接返回重写后的URI给客户端。

      flag:用来设置rewrite对URI的处理行为,可选值有如下:

      • last: 终止执行rewrite模块指令集,并开始搜寻重写url后匹配的location
      • break:终止执行rewrite模块指令集
      • redirect:临时重定向
      • permanent:永久重定向
      • 案例
        server{
          listen  8077;
          server_name localhost;
          location / {
            rewrite ^/test1 /test3 last;
            rewrite ^/test2 /test4 break;
            rewrite ^/test5 /test6 redirect;
            rewrite ^/test7 /test6 permanent;
          }
          location /break/ {
            rewrite ^/break/(.*) /test break;
            # echo需要安装第三方模块 echo-nginx-module
            # git clone https://codechina.csdn.net/mirrors/agentzh/echo-nginx-module.git
            echo "break page";
          } 
          location /test3 {
            return 200 "/test3";
          }
          location /test4 {
            return 200 "/test4";
          }
          location /test6 {
            return 200 "/test6";
          }
        }
        
        • 访问请求
          1. 访问[http://172.41.100.15:8077/test1](http://172.41.100.15:8077/test1) 返回 /test3

          访问/test1被重写为/test3,因为flag为last,所以发起一次location匹配,匹配到location /test3 {},所以最终返回结果为http200及/test3;

          1. 访问[http://172.41.100.15:8077/test2](http://172.41.100.15:8077/test2) 返回 404

          访问/test2,虽然/test2被重定向到/test4,但是break指令不会重新开启一个新的请求继续匹配,所以nginx是不会匹配到下面的/test/这个location,nginx尝试找/test4这个html页面并输出起内容,事实上,这个页面不存在,所以会报404的错误。可以看error.log

          2021/08/18 10:15:19 [error] 29936#0: *7 open() "/home/nginx/html/test4" failed (2: No such file or directory), client: 172.41.100.13, server: localhost, request: "GET /test2 HTTP/1.1", host: "172.41.100.15:8077"
          
          1. 访问http://172.41.100.15:8077/test5 返回 /test6

          访问/test1被重写为/test6,因为flag为redirect,地址栏被重写为http://172.41.100.15:8077/test6 http状态码为302 临时重定向,浏览器发起两次请求,一次/test5,一次/test6

          1. 访问[http://172.41.100.15:8077/test7](http://172.41.100.15:8077/test5) 返回 /test6

          访问/test1被重写为/test7,因为flag为permanent,地址栏被重写为[http://172.41.100.15:8077/test6](http://172.41.100.15:8077/test6) http状态码为301 永久重定向,浏览器发起两次请求,一次/test7,一次/test6

          1. 访问http://172.41.100.15:8077/break/6返回 break page

          break是跳过当前请求的rewrite阶段,并继续执行本请求的其他阶段,对于/break/对应的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的错误。

          • URL和URI的区别:

            URI:统一资源标识符

            URL:统一资源定位符

            rewrite_log指令

            配置是否开启URL重写日志的输出功能。

            语法rewrite_log on|off;
            默认值rewrite_log off;
            位置http、server、location、if

            开启后,URL重写的相关日志将以notice级别输出到error_log指令配置的日志文件汇总。

            • 案例
              server{
                      rewrite_log on;
                		  # 重定向error_log地址 
                      error_log /home/rewrite.log info;
                      listen  8077;
                      server_name localhost;
              }
              

              日志输出,notice都是重定向日志

              配合防盗链使用

              使用rewrite将盗链请求转发到自定义的一张图片和页面,给用户比较好的提示信息。

              1. 添加一张图片或者页面做提示展示

              在172.41.100.14的nginx目录中添加403图片

              1. 根据防盗链条件重定向盗链请求
              server{
               listen 9088;
               server_name localhost;
               location /images {
                  valid_referers none blocked server_names 127.0.0.1;
                  if ($invalid_referer){
                    # 重定向到指定图片
                    rewrite ^/ http://172.41.100.14:9088/403/403.jpg;
                  }
                  root /usr/local/nginx/html;
                }
              }
              
              1. 效果展示

              原请求被重定向到403页面了。

              目录合并

              网站中有一个资源文件的访问路径时 /server/11/22/33/44/20.html,也就是说20.html存在于第5级目录下,如果想要访问该资源文件,客户端的URL地址就要写成 http://172.41.100.15/server/11/22/33/44/20.html,这个是非常不利于SEO搜索引擎优化的,同时客户端也不好记,使用rewrite可以进行如下配置

              server {
              	listen 80;
              	server_name localhost;
              	location /server{
              		rewrite ^/server-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /server/////.html last;
              	}
              }
              

              客户端只需要输入http://172.41.100.15/server-11-22-33-44-20.html就可以访问到20.html页面了。这里也充分利用了rewrite指令支持正则表达式的特性。

The End
微信