使用 nginx 实现根据 header 进行静态资源的路由

使用 nginx 实现根据 header 进行静态资源的路由

背景

在开发过程中,希望针对静态资源进行动态切换,做一个灰度发布部署的功能,即区分主干环境与分支环境,根据请求的 header 中是否带有指定的字段(X-ENV-ID)来进行静态资源的路由。

实现

整体的架构图如下:

framework

实现方式: 通过 nginx 本身的特性实现,先将 header 中的变量映射到对应的目录,在 location 中使用变量定义 root 目录,再通过 try_files .. @fallback 对分支环境中不存在的资源,转到默认目录(主干)上去寻找资源,如果还找不到,则返回404.

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    map $http_x_env_id $resource_directory {

        default /usr/share/nginx/html/env0;  # 默认静态文件资源目录
        0 /usr/share/nginx/html/env0;  # 默认静态文件资源目录,
        1 /usr/share/nginx/html/env1;  # 根据header值为value1转发到资源1的静态文件目录
        2 /usr/share/nginx/html/env2;  # 根据header值为value2转发到资源2的静态文件目录
 
    }

    server {
        listen       80;
        server_name  localhost;

        location / {
            root $resource_directory;  # 根据header值动态选择静态文件资源目录
            try_files $uri $uri/ @fallback;  # 尝试查找资源,如果找不到则跳转到 @fallback
        }


        location @fallback {
            root /usr/share/nginx/html/env0/;
            try_files $uri $uri/ =404;  # 尝试查找资源,如果找不到返回404错误
        }

    }
}

案例:

  • 环境要求:docker,本机 80 端口没被占用
  • 运行: 执行 command.sh 脚本,打包 frontend 中的代码到 nginx 并执行,会启动 nginx 服务,监听 80 端口

主干&分支环境目录如下

├── env0
│   ├── index.html
│   └── static
│       ├── css
│       │   └── style.css
│       ├── img
│       │   └── image1.jpg
│       └── js
│           └── script.js
├── env1
│   ├── index.html
│   └── static
│       ├── css
│       │   └── style.css
│       ├── img
│       │   └── image1.jpg
│       └── js
│           └── script.js
├── env2
│   ├── index.html
│   └── static
│       ├── css
│       │   └── style.css
│       ├── img
│       └── js

其中, env0为主干环境,包括全量资源,env1为分支1环境,为全量的分支,env2为分支环境2,为部分的分支,因此当进入到 env1 环境时,访问的所有资源都是 env1 的资源,而当进入 env2 环境时, js 和 img 资源会使用主干环境的资源。

主干环境

分支环境1

分支环境2

proxy_pass 的转发

如果静态资源的存储不是使用本地存储,而是通过另一个文件服务来访问,那么在 nginx 中需要使用 proxy_pass 进行转发,此时要实现同样的静态资源路由功能, 对应转发配置如下:

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    map $http_x_env_id $backend {

        default http://127.0.0.1:8000;  # 默认静态文件资源目录
        0 http://127.0.0.1:8000;  # 默认静态文件资源目录,
        1 http://127.0.0.1:8001;  # 根据header值为value1转发到资源1的静态文件目录
        2 http://127.0.0.1:8002;  # 根据header值为value2转发到资源2的静态文件目录
 
    }

    server {
        listen       80;
        server_name  localhost;

        location / {
            proxy_pass $backend;
            proxy_intercept_errors on;
            error_page 404 = @fallback;
        }


        location @fallback {
            proxy_pass http://127.0.0.1:8000;
        }

    }
}
posted @ 2023-06-28 16:45  coreylin  阅读(690)  评论(0编辑  收藏  举报