首页/发现新知
视界 · 深度阅读

Nginx中Rewrite 重写与 Referer 防盗链实战

本文深入讲解Nginx rewrite模块核心指令(if、set、break、return)及rewrite重写规则,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

目录
  • 1.1 rewrite 模块核心指令
    • 1.1.1 if 条件判断指令
    • 1.1.2 set 变量赋值指令
    • 1.1.3 break 终止重写指令
    • 1.1.4 return 返回指令
  • 1.2 rewrite 重写指令
    • 常用正则速查表
    • 1.2.1 rewrite 四种 flag 详解
      • redirect(302 临时重定向)示例
      • permanent(301 永久重定向)示例
      • break 和 last 对比实验
  • 1.3 Rewrite 生产实战案例
    • 案例 1:全站 HTTP 自动跳转 HTTPS
      • 案例 2:访问不存在页面,跳转首页
      • 1.4 Nginx Referer 防盗链
        • 原理说明
          • 1.4.1 模拟盗链
            • 1.4.2 防盗链配置

            配套模块:ngx_http_rewrite_module前置依赖:PCRE 库(正则支持,编译 Nginx 时必须预先安装) 官方文档:https://nginx.org/en/docs/http/ngx_http_rewrite_module.html

            URL 重写是 Nginx 非常核心的高级能力,也是生产环境高频使用的功能。它可以在网站目录结构调整后,保证旧链接依然可用,不需要访客修改书签、外部站点也不用改动引用链接;同时结合 Referer 校验,还能实现资源防盗链,保护图片、视频等静态资源,节省服务器带宽。

            1.1 rewrite 模块核心指令

            rewrite 模块包含if、set、break、return、rewrite五条核心指令,指令结尾必须带分号。

            ⚠️ 重要限制:Nginx 的if不支持 if /else/elif,仅支持单次条件判断,多分支场景需要写多个独立 if 块。

            1.1.1 if 条件判断指令

            语法:

            if (条件) {
                配置动作;
            }

            支持的匹配符号说明:

            符号 说明
            = 字符串相等,匹配成功为 true
            != 字符串不相等,匹配成功为 true
            ~ 区分大小写正则匹配
            !~ 区分大小写,正则不匹配为 true
            ~* 不区分大小写正则匹配(最常用)
            !~* 不区分大小写,正则不匹配为 true
            -f / !-f 判断文件是否存在 / 不存在
            -d / !-d 判断目录是否存在 / 不存在
            -e / !-e 判断文件、目录、软链接是否存在 / 不存在
            -x / !-x 判断文件是否可执行 / 不可执行

            补充规则:变量值为空字符串或者数字 0 时,if 判定为 false;老版本 Nginx(1.0.1 前)以 0 开头的字符串也会判定 false。

            配置示例

            server {
                listen 80;
                server_name www.doubledragon.org;
                root /webdata/nginx/doubledragon.org;
                location /test {
                    index index.html;
                    default_type text/html;
                    if ( $scheme = http ){
                        echo "if -- $scheme";
                    }
                    if ( $scheme = https ){
                        echo "if -- $scheme";
                    }
                }
                location /app {
                    if ( !-e $request_filename ){
                        echo "$request_filename is not exist";
                    }
                }
            }

            测试:

            curl www.doubledragon.org/test
            # 输出:if -- http
            curl www.doubledragon.org/app
            # 输出:/webdata/nginx/doubledragon.org/app is not exist

            1.1.2 set 变量赋值指令

            用于自定义变量,值可以是固定文本、Nginx 内置变量,或者两者组合。 语法:set $key value;

            示例:

            location /test {
                set $name dragon;
                echo $name;
            }
            curl www.doubledragon.org/test
            # 输出:dragon

            1.1.3 break 终止重写指令

            在同一个server/location/if块内,遇到break,当前块后续所有 rewrite 模块指令不再执行;非 rewrite 模块指令不受影响。

            示例:

            location /break {
                default_type text/html;
                set $name dragon;
                echo $name;
                break;
                set $port $server_port;
                echo $port;
            }

            带 break 访问结果:

            curl www.doubledragon.org/break
            # dragon

            注释掉 break 后访问:

            curl www.doubledragon.org/break
            # dragon
            # 80

            1.1.4 return 返回指令

            直接终止本次请求,返回状态码、文本或者跳转 URL,return 之后所有配置不再执行。 三种语法:

            return code;                  # 仅返回状态码
            return code "提示内容";        # 返回状态码+文本
            return code https://url;       # 301/302跳转

            示例:文件不存在则 301 跳转百度

            location /return {
                default_type text/html;
                if ( !-e $request_filename ){
                    return 301 http://www.baidu.com;
                }
                echo "$request_filename is exist";
            }

            curl 测试会收到 301 响应头,浏览器访问直接跳转百度。

            1.2 rewrite 重写指令

            语法:rewrite regex replacement [flag]; 逻辑:使用正则匹配请求 URI,匹配成功就替换为新 URI;同一块内多条 rewrite 从上到下依次执行,替换后会重新发起一轮匹配循环,最多循环 10 次,超过直接返回 500 错误。

            如果替换地址以http://或https://开头,Nginx 直接向外返回重定向。

            常用正则速查表

            元字符 含义
            . 匹配任意非换行字符
            ^ 字符串开头
            $ 字符串结尾
            * 前面字符重复 0 次或多次
            + 前面字符重复至少 1 次
            ? 前面字符 0 或 1 次
            () 分组捕获,$1 $2调用分组内容
            \d 数字
            \w 字母、数字、下划线

            1.2.1 rewrite 四种 flag 详解

            flag 作用 跳转类型 说明
            redirect 302 临时重定向 客户端跳转 返回 302,浏览器重新发起请求,浏览器不缓存跳转记录
            permanent 301 永久重定向 客户端跳转 返回 301,浏览器缓存跳转记录,长期域名迁移使用
            break 停止当前 location 重写,直接使用新 URI 找资源 服务端内部 不再执行当前 location 后续 rewrite,直接匹配资源,location 中最常用
            last 停止当前 location 重写,用新 URI 重新全量匹配所有 location 服务端内部 适合多轮重写场景,不建议 location 中随便使用,容易循环

            redirect(302 临时重定向)示例

            location / {
                rewrite / http://www.baidu.com redirect;
            }
            curl -I www.doubledragon.org
            HTTP/1.1 302 Moved Temporarily
            Location: http://www.baidu.com

            permanent(301 永久重定向)示例

            适合域名永久更换(例如老域名彻底弃用)

            location / {
                rewrite / http://www.baidu.com permanent;
            }
            curl -I www.doubledragon.org
            HTTP/1.1 301 Moved Permanently
            Location: http://www.baidu.com

            区分重点:301 会被浏览器缓存,就算后端 Nginx 挂了,本地缓存依然会跳转;302 不缓存,每次都询问服务端。

            break 和 last 对比实验

            提前准备目录与页面:

            mkdir /webdata/nginx/doubledragon.org/{break,last,test1,test2}
            echo break > /webdata/nginx/doubledragon.org/break/index.html
            echo last > /webdata/nginx/doubledragon.org/last/index.html
            echo test1 > /webdata/nginx/doubledragon.org/test1/index.html
            echo test2 > /webdata/nginx/doubledragon.org/test2/index.html

            break 配置:重写后停止本 location 剩下 rewrite,不再重新匹配 location

            location /break {
                rewrite /break/(.*) /test1/$1 break;
                rewrite /test1 /test2; # 本条不会执行
            }
            location /test1 {
                return 200 "test1 end page";
            }
            location /test2 {
                return 200 "test2 end page";
            }

            访问结果:www.doubledragon.org/break/ 返回 test1 end page

            last 配置:重写结束,拿着新 URI 从头重新匹配全部 location

            location /break {
                rewrite /break/(.*) /test1/$1 last;
                rewrite /test1 /test2; # 本条不会执行
            }
            location /test1 {
                return 200 "test1 end page";
            }
            location /test2 {
                return 200 "test2 end page";
            }

            访问结果同样返回 test1 end page;如果规则改成匹配 /test1 再转到 test2,last 才会触发第二轮匹配。

            1.3 Rewrite 生产实战案例

            案例 1:全站 HTTP 自动跳转 HTTPS

            先自签 SSL 证书(测试环境)

            mkdir /webdata/nginx/doubledragon.org/certs
            openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
            -keyout /webdata/nginx/doubledragon.org/certs/doubledragon.org.key \
            -out /webdata/nginx/doubledragon.org/certs/doubledragon.org.crt
            # Common Name填写:www.doubledragon.org

            配置文件:

            server {
                listen 443 ssl;
                listen 80;
                ssl_certificate /webdata/nginx/doubledragon.org/certs/doubledragon.org.crt;
                ssl_certificate_key /webdata/nginx/doubledragon.org/certs/doubledragon.org.key;
                ssl_session_cache shared:sslcache:20m;
                ssl_session_timeout 10m;
                server_name www.doubledragon.org;
                location / {
                    root /webdata/nginx/doubledragon.org/instance1;
                    index index.html;
                    # 判断http协议,避免https继续跳转造成死循环
                    if ($scheme = http){
                        rewrite / https://$host redirect;
                    }
                }
                # 单独对/login路径强制https
                location /login {
                    if ($scheme = http){
                        rewrite / https://$host/login redirect;
                    }
                }
            }

            测试:

            curl -ikL www.doubledragon.org
            # 先收到302,再返回200,页面内容instance1

            案例 2:访问不存在页面,跳转首页

            在上面 HTTPS 配置的location /内追加判断:

            if (!-e $request_filename){
                rewrite .* https://www.doubledragon.org/index.html redirect;
            }

            测试访问一个不存在页面 www.doubledragon.org/index1.html,自动跳转到网站首页,替代原生 404 页面,提升用户体验。

            1.4 Nginx Referer 防盗链

            原理说明

            防盗链依靠请求头Referer实现:这个头部记录访客是从哪个页面跳转过来访问资源。盗链就是第三方网站直接嵌入我方图片、视频等静态资源,消耗我方带宽。

            valid_referers 支持的类型:

            • none:请求不带 Referer 头(用户直接在地址栏输入地址访问)
            • blocked:Referer 存在但是为空、无效值
            • server_names:本机配置的 server_name,本站内部访问
            • *.doubledragon.org:通配域名
            • ~开头:正则匹配

            1.4.1 模拟盗链

            在另一台 Nginx 主机 Nginx2 上写页面,直接引用本站图片:

              
                
                盗链
              
              
                Nginx中Rewrite 重写与 Referer 防盗链实战
                

            欢迎大家

            狂点dragon出门见喜

            不做防盗链时,第三方站点可以正常加载图片资源。

            1.4.2 防盗链配置

            server {
                listen 80;
                server_name www.doubledragon.org;
                root /webdata/nginx/doubledragon.org;
                # 全站校验referer,非法访问返回404
                location / {
                    valid_referers none blocked server_names *.doubledragon.org ~.baidu.;
                    if ($invalid_referer){
                        return 404;
                    }
                }
                # 图片目录防盗链,盗链时返回一张提示图
                location /img {
                    valid_referers none blocked server_names *.doubledragon.org ~.baidu.;
                    if ($invalid_referer){
                        rewrite ^/ http://www.doubledragon.org/daolian/daolian.png;
                    }
                }
            }

            配置重载后,第三方盗链站点无法加载原图,会返回 404 或者替换为防盗提示图片,达到保护静态资源的效果。

            到此这篇关于Nginx中Rewrite 重写与 Referer 防盗链实战的文章就介绍到这了,更多相关Nginx Rewrite重写与 Referer 防盗链内容请搜索爱读视界以前的文章或继续浏览下面的相关文章希望大家以后多多支持爱读视界!

            您可能感兴趣的文章:

            • Nginx之rewrite实现URL重写方式
            • Nginx rewrite地址重写的详细解析
            • Nginx之location匹配和Rewrite重写跳转方式
            • Nginx之rewrite重写的具体使用
            • nginx Rewrite重写地址的实现
            • Nginx的重写Rewrite使用示例分析
            • Nginx中location匹配以及rewrite重写跳转详解
            • Nginx URL重写rewrite机制原理及使用实例
            • Nginx rewrite正则匹配重写的方法示例
            • 详解常用的nginx rewrite重写规则
            • nginx rewrite重写规则与防盗链配置方法教程详解
            • nginx重写rewrite基础及实例分享
            • WordPress与Drupal的Nginx配置rewrite重写规则示例
            • Nginx服务器下使用rewrite重写url以实现伪静态的示例
            读到这里,发现更多一点。探索更多内容 ↗