美文网首页
9. Nginx Rewrite 功能

9. Nginx Rewrite 功能

作者: 随便写写咯 | 来源:发表于2021-03-18 20:21 被阅读0次

    Nginx服务器利用ngx_http_rewrite_module模块解析和处理rewrite请求, 此功能依靠PCRE, 因此编译之前要安装PCRE库, rewrite是nginx服务器的重要功能之一, 用于实现URL的重写. URL的重写是非常有用的功能, 比如它可以在我们改变网站结构之后, 不需要客户端修改原来的书签, 也无需其他网站修改我们的链接, 就可以设置为访问, 另外还可以在一定程度上提高网站的安全性

    5.1 ngx_http_rewrite_module 模块指令

    5.1.1 if 指令

    用于条件匹配判断, 并根据条件判断结果, 选择不同的Nginx配置, 可以配置在server或location语句块中
    Nginx的if语法仅能使用if做单次判断, 不支持使用if else或者if elif这样的多重判断, 用法如下:

    if (条件匹配){
      action
    }
    

    使用正则表达式对变量进行匹配, 匹配成功时, if指令认为条件为true, 否则认为是false, 变量与表达式之间使用以下符号链接:

    = 比较变量和字符串是否相等, 相等时if指令认为该条件为true, 反之为false
    != 比较变量和字符串是否不相等, 不相等时if指令认为条件为true, 反之为false
    ~ 区分大小写字符, 可以通过正则表达式匹配, 满足匹配条件为真, 不满足匹配条件为假
    !~ 区分大小写字符, 判断是否匹配, 不满足匹配条件为真, 满足匹配条件为假
    ~* 不区分大小写字符, 可以通过正则表达式匹配, 满足匹配条件为真, 不满足匹配条件为假
    !~* 不区分大小写字符, 判断是否匹配, 满足匹配条件为假, 不满足匹配条件为真
    
    -f 和 !-f 判断请求的文件是否存在和是否不存在
    -d 和 !-d 判断请求的目录是否存在和是否不存在
    -x 和 !-x 判断文件是否可执行和是否不可执行
    -e 和 !-e 判断请求的文件或目录是否存在和是否不存在(包括文件, 目录, 软连接)
    
    • 范例: 判断请求的uri中的$shceme, 协议
    [13:46:30 root@nginx ~]#vim /apps/nginx/conf.d/pc.conf 
    
        location /main {
            index index.html;
            default_type text/html;                                                                                                                                                     
            if ( $scheme = http ){  # 添加了if判断后, 原本的页面信息就不会显示了
                echo "if -----> $scheme";
            }
            if ( $scheme = https ){
                echo "if -----> $scheme";
            }
        
        }
    
    
    [13:48:24 root@nginx ~]#curl pc.wang.org/main
    if -----> http   # 注意: 一旦匹配成功后, 原本的页面信息是不会显示的, 只会执行action中的操作, 并显示其结果
    
    [13:58:39 root@nginx ~]#curl https://pc.wang.org/test -k
    if -----> https
    
    • 范例: 判断请求的文件是否存在
        location /main {
            index index.html;
            default_type text/html;
    
            if ( !-e $request_filename ){
            
                echo "$request_filename does not exist!";
            }                                                                                                                                                                           
        
        }
    
    
    [14:02:25 root@nginx ~]#curl pc.wang.org/main/index.html 
    /apps/nginx/html/main/index.html does not exist!
    
    # 创建index.html文件
    [14:02:30 root@nginx ~]#mkdir /apps/nginx/html/main
    [14:02:53 root@nginx ~]#echo /apps/nginx/html/main/index.html > /apps/nginx/html/main/index.html
    [14:03:51 root@nginx ~]#nginx -s reload
    [14:03:53 root@nginx ~]#curl pc.wang.org/main/index.html 
    /apps/nginx/html/main/index.html
    # 再次访问会显示页面内容
    

    补充: 如果使用了if判断, 那么echo $变量必须放在if语句块才能生效

    如果$变量的值为空字符串或者以0开头的任意字符串, 则if指令认为该条件为false, 其他条件为true

    5.1.2 set 指令

    指定key并给其定义一个变量, 变量可以调用Nginx内置变量赋值给key, 另外set定义格式为set $key value

    范例:

        location /test {
            index index.html;
            default_type text/html;
            set $name admin;
            echo $name;
            set $web $host;
            echo $web;
        }
    
    
    [14:19:12 root@nginx ~]#nginx -s reload
    [14:19:14 root@nginx ~]#curl pc.wang.org/test
    admin
    pc.wang.org
    
    

    5.1.3 break 指令

    用于中断当前相同作用域(location, server, if)中的后续的rewrite模块中的指令, 一般用在location, 与该指令处于同一个作用域的Nginx中, 位于它前面的rewrite指令配置生效, 位于后面的 ngx_http_rewrite_module 模块中的指令就不再执行

    • 范例:
        location /break {
        
            root /data/nginx/html/pc;
            index index.html;
            default_type text/html;
            set $name admin;
            echo $name;
            break;
            set $port_num $server_port; # break后的set指令不会执行
            echo $port_num; # echo并不属于rewrite模块, 因此echo $port_num还会执行, 但是因为port_num并没有被赋值, 因此返回空
        
        }
    
    
    [14:26:29 root@nginx ~]#curl pc.wang.org/break
    admin
    
    

    5.1.4 return 指令

    return用于完成对请求的处理, 并直接向客户端返回响应状态码而非实际的页面内容, 同时, return前后的命令也都不会执行. 也就是只执行return命令 比如: 可以指定重定向URL(对于特殊重定向状态码, 301/302等)或者是指定提示文本内容(对于特殊状态码403/500等), 处于此指令后的所有Nginx配置都将不被执行, return可以在server, if和location语句块进行配置

    return后可以接响应码, 直接返回给客户端, 也可以接响应码和提示信息, 返回给客户端, 或者接URL跳转, 通过301或者302跳转到其他链接

    如果break和return同时出现, 那么return放在break后面时, 也不会执行, 因为return也属于rewrite的命令

    • 范例: 自定义响应码
    [14:27:11 root@nginx ~]#vim /apps/nginx/conf.d/pc.conf
        location /break {
    
            root /data/nginx/html/pc;
            index index.html;
            default_type text/html;
            return 88;                                   # 直接返回响应码, 后续命令不再执行, 也不会返回页面内容                                                                                                                              
            set $name admin;
            echo $name;
            break;
            set $port_num $server_port;
            echo $port_num;
    
        }
    
    [14:37:40 root@nginx ~]#nginx -s reload
    [14:37:44 root@nginx ~]#curl -I pc.wang.org/break
    HTTP/1.1 088  # 自定义的响应码88
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 06:37:52 GMT
    Content-Type: text/html
    Content-Length: 0
    Connection: keep-alive
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    
    
    
    • 范例: 通过return自定义返回结果
        location /break {
    
            root /data/nginx/html/pc;
            index index.html;
            default_type text/html;
            return 88 "return result";                                                                                                                                                  
            set $name admin;
            echo $name;
            break;
            set $port_num $server_port;
            echo $port_num;
    
        }
    
    
    [14:42:48 root@nginx ~]#curl pc.wang.org/break
    return result[14:42:59 root@nginx ~]#curl pc.wang.org/break -I
    HTTP/1.1 088 
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 06:43:02 GMT
    Content-Type: text/html
    Content-Length: 13
    Connection: keep-alive
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    
    
    • 范例: return跳转到其他的URL
        location /break {
        
            root /data/nginx/html/pc;
            index index.html;
            default_type text/html;
            return 301 http://www.baidu.com;         # 需要指定return 301或者302,  否则浏览器不会真的跳转                                                                                                                                
            set $name admin;
            echo $name;
            break;
            set $port_num $server_port;
            echo $port_num;
             
        }
    
    
    图片.png
    • 范例: 实现主站点的https自动跳转
        location  / {                                                                                                                                                        
            root /data/nginx/html/pc;
            return 302 https://pc.wang.org;                                                                                                                                             
        }
    
    

    由于没有做其他配置, 此时跳转会出现死循环, 第一次访问/时会跳转到https, 虽然跳转到了https, 但是仍然访问的是根, 又继续跳转, 进入死循环

    详解: 第一次无论是访问http还是https, 由于都是访问的主站点/, 因此都会执行跳转到https, 跳转到https后, 仍然访问的是/, 因此会无限跳转, 直到超过跳转次数. 需要配置if条件, 来进行判断, 如果访问的是https, 那么就不跳转, 稍后演示

    图片.png
    • 配置HSTS
     add_header Strict-Transport-Security "max-age=3153600; includeSubDomains" always;
    
    [16:43:48 root@nginx ~]#vim /apps/nginx/conf.d/pc.conf 
    
    server {
    
        listen 80;
        listen 443 ssl;
        add_header Strict-Transport-Security "max-age=3153600; includeSubDomains" always; 
    
    [16:46:49 root@nginx ~]#nginx -s reload
    

    5.1.5 rewrite_log 指令

    设置是否开启记录ngx_http_rewrite_module 模块日志记录到error_log日志文件当中, 可以配置在http, server, location或者if中
    记录的是rewrite出现的错误日志

    注意: 需要日志级别设定为notice

    # 修改日志记录级别
    
       error_log /data/nginx/logs/pc_wang_org_error.log notice; 
    
    # 修改配置文件记录重写日志
    
        location /break {
        
            root /data/nginx/html/pc;
            index index.html;
            default_type text/html;
            rewrite_log on;                                                                                                                                                             
            set $name admin;
            echo $name;
            break;
            set $port_num $server_port;
            echo $port_num;
             
        }
    
    
    # 上述配置中, 由于出现了break, 那么后续的set命令不会执行, 但是echo命令不受影响, 不过echo的变量是没有赋值的, 因此算作重写错误, 会记录到error_log
    2021/03/18 15:08:56 [warn] 1667#0: *54 using uninitialized "port_num" variable, client: 10.0.0.86, server: pc.wang.org, request: "GET /break HTTP/1.1", host: "pc.wang.org"
    
    

    5.2 rewrite 指令

    通过正则表达式的匹配来改变URI, 可以同时存在一个或多个指令, 按照顺序依次对URI进行匹配, rewrite主要是针对用户请求的URL或者URI做具体处理

    rewrite可以匹配在server, location, if语句块中

    语法格式:

    rewrite regex replcement [flag];
    

    rewrite将用户请求的URI基于regex所描述的模式进行检查, 如果匹配, 会将URI替换为其表达式指定的新的URI

    注意: 如果在同一级别配置块中, 存在多个rewrite规则, 那么会自上而下逐个检查, 被某条件规则替换完成后, 会重新一轮的替换检查, 隐含循环机制, 但不会循环超过10次, 如果超过, 会提示500响应码, [flag]所表示的标志位用于控制此循环机制

    如果替换后的URL是以http://或者https://开头, 则替换结果会直接以重定向返回给客户端, 即永久重定向301

    正则表达式格式:

    .  匹配除换行符以外的任意字符
    \w 匹配字母或数字或下划线或汉字
    \s 匹配任意的空白符
    \d 匹配数字
    \b 匹配单词的开始或结束
    ^  匹配字符串的开始
    $  匹配字符串的结束
    *  匹配重复0次或更多次
    +  匹配重复1次或更多次
    ?  匹配重复0次或1次
    (n) 匹配重复n次
    {n,} 匹配重复n次或更多次
    {n,m} 匹配重复n到m次
    *? 匹配重复任意次, 但尽可能少重复
    +? 匹配重复1次或更多次, 但尽可能少重复
    ?? 匹配重复0次或1次, 但尽可能少重复
    {n,m}? 匹配重复n到m次, 但尽可能少重复
    {n,}? 匹配重复n次以上, 但尽可能少重复
    \W 匹配任意不是字母, 数字, 下划线, 汉字的字符
    \S 匹配任意不是空白符的字符
    \D 匹配任意非数字的字符
    \B 匹配不是单词开头或结束的位置
    [^x] 匹配除了x以外的任意字符
    [^admin] 匹配除了admin这几个字母以外的任意字符
    

    5.2.1 rewrite flag 使用介绍

    利用nginx的rewrite的指令, 可以实现url的重新跳转, rewrite有四种不同的flag, 分别是redirect(临时重定向), permanent(永久重定向), break和last.

    其中, 前两种是跳转型的flag, 后两种是代理型, 跳转型指由客户端浏览器重新对新地址进行请求, 代理型是WEB服务器内部实现跳转

    Syntax: rewrite regex replacement [flag]; # 通过正则表达式处理用户请求并返回替换后的数据包
    Default:    —
    Context:    server, location, if
    
    redirect;
    临时重定向, 重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端, 由客户端重新发起请求; 使用相对路径, 或者http://或者https://开头, 状态码:302
    
    permanent;
    重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端, 由客户端重新发起请求, 状态码: 301
    
    last;
    重写完成后, 停止对当前URI在当前location中后续的其他重写操作, 而后对新的URL启动新一轮重写检查, 不建议在location中使用
    适用于一个URL多次重写, 要注意避免出现超过10次以及URL重写后返回错误的URL给用户
    
    break;
    重写完成后, 停止对当前URL在当前location中后续的其他重写操作, 至于重写后的URL, 如果在其他location中有匹配, 那么也不会执行, break就是直接结束循环, 只要遇到了break, 那么就会结束匹配, 并且执行break前rewrite定义的操作, 建议在location中使用
    适用于一个URL一次重写
    

    5.2.2 rewrite 案例: 域名永久和临时重定向

    域名的临时调整, 后期可能会发生变化, 之前的域名或者URL可能还会使用, 或者跳转的目地域名和URL还会跳转, 这种情况下浏览器不会缓存跳转, 临时重定向不会缓存域名解析A记录, 而永久重定向会缓存

    5.2.2.1 永久重定向

    域名永久型调整, 即域名永远跳转至另一个新的域名, 之前的域名再也不使用, 跳转记录可以缓存到客户端浏览器

    永久重定向会缓存DNS解析记录, 浏览器中请求报文头部会有from disk cache信息

    • 范例: 将pc.wang.org, 临时跳转到m.wang.org
        location  / {
            root /data/nginx/html/pc;
            rewrite / http://m.wang.org permanent;                                                                                                                                      
        }
    
    [17:22:17 root@nginx ~]#curl -I pc.wang.org
    HTTP/1.1 301 Moved Permanently
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 09:22:24 GMT
    Content-Type: text/html
    Content-Length: 169
    Connection: keep-alive
    Location: http://m.wang.org
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    
    [17:22:24 root@nginx ~]#curl -L pc.wang.org
    mobile website
    

    5.2.2.2 临时重定向

    域名临时重定向, 告诉浏览器域名不是固定重定向到当前目标域名, 后期可能随时会更改, 因此浏览器不会缓存当前域名的解析记录, 而浏览器会缓存永久重定向的DNS解析记录, 这也是临时重定向与永久重定向最大的本质区别

    • 范例: 将pc.wang.org, 临时跳转到m.wang.org
        location  / {                                                                                                                                                        
            root /data/nginx/html/pc;
            rewrite / http://m.wang.org redirect;                                                                                                                                       
        }
    
    
    [17:17:20 root@nginx ~]#curl pc.wang.org
    <html>
    <head><title>302 Found</title></head>
    <body>
    <center><h1>302 Found</h1></center>
    <hr><center>nginx/1.18.0</center>
    </body>
    </html>
    [17:17:49 root@nginx ~]#curl pc.wang.org -I
    HTTP/1.1 302 Moved Temporarily
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 09:17:53 GMT
    Content-Type: text/html
    Content-Length: 145
    Connection: keep-alive
    Location: http://m.wang.org
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    
    
    [17:18:42 root@nginx ~]#curl pc.wang.org -L
    mobile website
    
    

    5.2.3 rewrite 案例: break 与 last

    5.2.3.1 break 案例

    # break测试案例: 当客户端访问break的时候, 测试通过rewrite将URL重写为test1, 然后再通过rewrite将test1重写为test2
    # 测试两条rewrite规则最终哪一条生效, 并且测试重写后的URL会不会到其他location重新匹配
    
        location /break {
        
            root /data/nginx/html/pc
            index index.html
            rewrite ^/break/(.*) /test1/$1 break;                # 将访问以/break/开头的所有请求, 重写到/test1目录对应的资源, 并立即停止匹配, break匹配成功后, 不会再向下匹配, 也不会跳转到其他的location, 即直接结束匹配并给客户端返回结果数据                                                                                                                     
            rewrite ^/test1/(.*) /test2/$1 break;                 # break不会匹配后面的rewrite规则, 也不会匹配其他的location
    
        }
    
        location /test1 {
            echo "new test1";
            return 999 "new test1";
        }
        
        location /test2 {
            echo "new test2";
            return 666 "new test2";
        }
    
    
    # 创建test1, test2和break目录
    
    [18:13:07 root@nginx ~]#echo break > /data/nginx/html/pc/break/index.html
    [18:13:20 root@nginx ~]#echo test1 > /data/nginx/html/pc/test1/index.html
    [18:13:27 root@nginx ~]#echo test2 > /data/nginx/html/pc/test2/index.html
    
    # break访问测试
    
    [18:19:26 root@nginx ~]#curl pc.wang.org/break/index.html  # 验证了一旦遇到了break就不会继续执行本层location内的其他指令, 也不会继续匹配其他location,
    test1
    
    [18:30:21 root@nginx ~]#curl pc.wang.org/break/index.html -i
    HTTP/1.1 200 OK # 响应码为200
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 10:30:31 GMT
    Content-Type: text/html
    Content-Length: 6
    Last-Modified: Thu, 18 Mar 2021 10:13:27 GMT
    Connection: keep-alive
    ETag: "605327c7-6"
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    Accept-Ranges: bytes
    
    test1
    
    

    注意: 如果访问的是http://pc.wang.org/break, 那么会显示new test111, 也就是rewrite到test1后继续到test1的location进行匹配执行

    • break适用场景:

    break适用于不改变客户端访问方式, 但是要将访问的目的URL做单次重写的场景, 比如: 有v1/v2两个版本的网站前端页面并存, 旧版本的网站数据在staticv1, 还不能丢失, 但是要将访问旧版本的请求重写到新的静态资源路径staticv2

    location /staticv1 {
    
      root /data/nginx;
      index index.html;
      rewrite ^/staticv1/(.*) /staticv2/$1 break; # 访问旧的路径会被重写到新的路径再响应
    }
    
    location /staticv2 { # 新的路径也可以直接响应新的请求
    
      root /data/nginx;
      index index.html;
    }
    

    5.2.3.2 last 案例

    last: 对某个location的URL匹配成功后, 会停止当前location的后续rewrite规则, 并结束当前location, 然后将匹配生成的新的URL跳转至其他location继续匹配, 直到没有location可以匹配, 将最后一次location的数据返回给客户端

    last适用于不改变客户端访问方式, 但是要求多次目的URL重写的场景, 使用场景不是很多

    • 范例:
        location /last {
        
            root /data/nginx/html/pc;
            index index.html;
            rewrite ^/last/(.*) /test1/$1 last; 
            rewrite ^/test1/(.*) /test2/$1 last; # 如果第一条rewrite规则匹配成功则不会继续执行本条rewrite, 否则执行本条rewrite规则
    
       }
    
       location /test1 {
            #echo "new test1";
            #return 999 "new test1";
            rewrite ^/test1/(.*) /test2/$1 last;
       }
        
       location /test2 {
            #echo "new test2";
            return 666 "new test222";
       }
    
    
    [18:55:14 root@nginx ~]#curl pc.wang.org/last/index.html
    new test222 # 会匹配多个location, 直到最终全部匹配完成, 返回最后一个location的匹配结果给客户端
    

    5.2.4 rewrite案例: 自动跳转https

    无论是使用return 还是 rewrite https, 都会出现死循环跳转, 导致页面无法访问的情况, 因此, 需要配合if条件判断, 防止死循环

    • 范例: 实现全站https, 在不影响用户请求的情况下, 将http请求全部自动跳转至https, 另外也可以实现部分location跳转
        location  / {
            root /data/nginx/html/pc;
            if ( $scheme = http ) {                    # 判断, 如果访问的是http, 那么才进行跳转, 如果不是http, 比如https那么就不跳转了, 这样来解决死循环的问题                                                                                                                                  
                rewrite / https://$host redirect;
            }
        }
    
    
    [17:39:05 root@nginx ~]#curl -ikL pc.wang.org 
    HTTP/1.1 302 Moved Temporarily
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 09:39:15 GMT
    Content-Type: text/html
    Content-Length: 145
    Connection: keep-alive
    Location: https://pc.wang.org
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    
    HTTP/1.1 200 OK
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 09:39:15 GMT
    Content-Type: text/html
    Content-Length: 11
    Last-Modified: Mon, 15 Mar 2021 12:57:27 GMT
    Connection: keep-alive
    ETag: "604f59b7-b"
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    Accept-Ranges: bytes
    
    pc website
    
    
    • 范例: 针对特定的location进行https跳转
        location  /login {
            root /data/nginx/html/pc;
            if ( $scheme = http ) {                                                                                                                               
                rewrite / https://$host/login redirect;
            }
        }
    

    5.2.5 rewrite 案例: 判断文件是否存在

    • 范例: 当用户访问了一个不存在的页面, 将请求重定向到首页
        location  / {
            root /data/nginx/html/pc;
            index index.html;
            if ( !-e $request_filename ){
                rewrite .* http://pc.wang.org/index.html;
            }
            if ( $scheme = http ){
                rewrite / https://pc.wang.org/index.html;                                                                                                                               
            }
        }
    
    
    [19:09:01 root@nginx ~]# nginx -t
    nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
    [19:09:02 root@nginx ~]# nginx -s reload
    
    
    [19:09:06 root@nginx ~]#curl -ikL pc.wang.org/xxx.html
    HTTP/1.1 302 Moved Temporarily
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 11:09:29 GMT
    Content-Type: text/html
    Content-Length: 145
    Connection: keep-alive
    Location: http://pc.wang.org/index.html  # 先将错误访问跳转到http主页面
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    
    HTTP/1.1 302 Moved Temporarily
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 11:09:29 GMT
    Content-Type: text/html
    Content-Length: 145
    Connection: keep-alive
    Location: https://pc.wang.org/index.html # 再将http访问跳转到https
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    
    HTTP/1.1 200 OK # 响应报文
    Server: nginx/1.18.0
    Date: Thu, 18 Mar 2021 11:09:29 GMT
    Content-Type: text/html
    Content-Length: 11
    Last-Modified: Mon, 15 Mar 2021 12:57:27 GMT
    Connection: keep-alive
    ETag: "604f59b7-b"
    Strict-Transport-Security: max-age=3153600; includeSubDomains
    Accept-Ranges: bytes
    
    pc website
    
    

    5.2.6 其他案例

    • 案例1: 根据不同的客户端浏览器, 重写请求到不同的目录, 利用内置变量($http_user_agent), 比如如果客户端浏览器包含MSIE, 那么就rewrite客户端请求到/msie目录下
    if ( $http_user_agent ~ MSIE ){
      rewrite ^(.*)$ /msie/$1 break;
    }
    
    • 案例2: 更换目录的访问方式, 目录转换为对象存储形式
    # 要求从: /20200106/static -> /static?id=20200106
    rewrite ^/(\d+)/(.+) /$2?id=$1 last;
    
    • 案例3: 多目录转换访问方式
    要求: pc.wang.org/images/20200106/1.jpg --> pc.wang.org/index.do?name=images&dir=20200106=&file=1.jpg
    
    #规则配置
    
    if ( $host ~* (.*)\.wang\.org) {
      rewrite ^/(.*)/(\d+)/(.*)$ /index.do?name=$1&dir=$2&file=$3 last;
    }
    

    5.3 Nginx 防盗链

    防盗链基于客户端请求报文携带的referer字段实现, referer是记录打开一个页面之前, 记录是从哪个页面跳转过来的标记信息, 如果别人只链接了其他网站的图片或者某个单独的资源, 而不是打开了整个网站页面, 那么就是盗链, referer字段显示的就是跳转之前的网站的域名, 正常的referer信息有以下几种:

    none: 请求报文首部没有referer字段,  比如用户直接在浏览器输入域名访问web网站, 这时就没有referer信息
    blocked: 请求报文有referer字段, 但无有效值, 比如为空
    server_names: referer字段中包含本主机名, 即nginx监听的server_name, 表示从自己的本网站调转而来
    arbitrary_string: 自定义指定字符串, 可以使用*做通配符, 范例: *.wang.org, pc.wang.*
    regular expression: 被指定的正则表达式模式匹配到的字符串, 要使用~开头, 例如: ~.*\.wang\.org 
    
    
    • 配置访问日志格式, 记录referer信息
    # 日志格式中的 "$http_referer" 会记录请求报文的referer字段信息, $http_name可以记录请求报文所有的字段信息
       log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                         '$status $body_bytes_sent "$http_referer" '
                         '"$http_user_agent" "$http_x_forwarded_for"';
    # 访问日志调用指定格式
        access_log /data/nginx/logs/pc_access.log main; 
    
    • 测试正常通过域名访问网站, pc.wang.org
    10.0.0.1 - - [18/Mar/2021:19:53:41 +0800] "GET /index.html HTTP/1.1" 200 11 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0" "-"
    
    
    图片.png
    "-": 表示直接在浏览器输入网站访问, 不是从其他网站跳转过来的
    
    如果显示URL+文件名, 说明是从其他链接跳转, 这时要分析是不是从自己的网站跳转还是从其他网站跳转
    
    如果显示搜索引擎, 也不算盗链
    

    5.3.1 实现防盗链

    可以基于整个虚拟主机做防盗链, 放在server语句块
    也可以基于某个location做防盗链, 放在location语句块
    
    • 范例: 对于pc.wang.org全站设置防盗链
    server {
        valid_referers none blocked server_names *.wang.org  ~\.google\. ~\.baidu\. ~\.bing\. ~\.so\. ;            # 定义有效的referer                                                                      
        if ( $invalid_referer ){
            return 403 "禁止盗链"; # 其余全部定义为无效的referer, 访问会返回403
        }
    }
    

    相关文章

      网友评论

          本文标题:9. Nginx Rewrite 功能

          本文链接:https://www.haomeiwen.com/subject/qxekcltx.html