V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
laev
V2EX  ›  NGINX

关于 lua 中对 nginx 变量处理后 proxy_pass 出现问题的疑问

  •  
  •   laev · 13 天前 · 500 次点击
    xdm 好,我是个前端,运维方面的菜鸡,请教大家一下

    我用 openresty 搭建了个简陋版本的灰度切换方案,但是 lua 脚本运行之后好像出了点问题

    -------------------------test.conf start-----------------------------
    upstream production_server {
    server 123.123.123.123:80;
    }
    upstream grayscale_server {
    server 456.456.456.456:80;
    }

    server {
    listen 80;
    server_name localhost;
    lua_code_cache off;
    set $default_stream "production_server";
    set $grayscale_stream "grayscale_server";
    # 运行脚本读取策略
    access_by_lua_file /usr/local/openresty/lua/main.lua;

    location / {
    default_type text/html;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_redirect off;
    proxy_pass $scheme://$default_stream;
    proxy_next_upstream http_500 http_503 error;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root /usr/local/openresty/nginx/html;
    }
    }
    -------------------------test.conf end-----------------------------

    -------------------------main.lua start-----------------------------
    local redisutils = require("redisutils")
    local controller = require("controller")
    local red = redisutils.redisClient()
    local params = ngx.req.get_uri_args()
    local userId = params.userId

    if red then
    local is_grayscale = controller.checkUserId(red, userId)
    if is_grayscale then
    ngx.var.default_stream = ngx.var.grayscale_stream
    end
    redisutils.closeRedis(red)
    end
    -------------------------main.lua end-----------------------------

    我把$default_stream 直接替换为“production_server” 或 “grayscale_server” 都没有问题
    但是 lua 运行后,大概是这一句 ngx.var.default_stream = ngx.var.grayscale_stream
    index.html 中的 js 和 css 等使用相对路径(“/js/xxx.js”)的资源都似乎回源到了代理机器本身,从而最终找不到资源

    如果哪位大佬有办法解决,希望不吝赐教一下,或者说有更好的方法也可以。

    感谢!!!
    第 1 条附言  ·  12 天前
    我大概知道了,在 conf 文件中
    access_by_lua_file /usr/local/openresty/lua/main.lua
    是非阻塞的,所以往下运行,当脚本没执行完最后 proxy_pass 代理的还是"production_server",而直接写死或通过简单赋值的修改,运行时间是比较快的,能够成功设置值。所以这才出现了那些现象。
    4 条回复    2021-11-29 10:28:21 +08:00
    eason1874
        1
    eason1874  
       13 天前
    静态文件链接不带 userId 参数吧,按你的代码,链接没有 userId 判断不了是否灰度

    但是判断不了也应该回源 production_server 啊,怎么会是代理机器呢,你确定没搞错?
    laev
        2
    laev  
    OP
       12 天前
    @eason1874 确实是我搞错了,最终回源到的是 production_server 。我有点疑问的是当$default_stream 为 production_server 也就是默认值的时候,静态文件是可访问的,似乎 nginx 自动处理了$args ,同时 $default_stream 替换为 grayscale_server 也是可以访问的。我尝试在配置文件中写入
    access_by_lua_block {
    ngx.var.default_stream = ngx.var.grayscale_stream
    }
    这样也能成功读取到,目前似乎是在引用 lua 脚本运行赋值时没有获得 userId 从而导致资源被指向 production_server
    eason1874
        3
    eason1874  
       12 天前
    @laev 你的代码根据网址参数 userId 判断是否灰度,静态文件链接没有这个参数啊

    比如你允许 userId 为 1 的灰度, 当请求 //localhost/?userId=1 时会匹配到灰度,但是网页里面的资源比如 /js/a.js 不会匹配到灰度,因为不是 /js/a.js?userId=1 ,缺少必要参数

    解决办法就是换别的方式传参。比如用 Cookies ,但是 Cookies 动态判断的缺点很多,客户端禁用 Cookies 的时候不管用,要在 CDN 缓存静态资源时不管用,等等

    所以不同版本的静态资源路径通常是写死的,部署自动在路径加上文件版本号,比如 /js/a-{filehash}.js ,新版本引用新的文件就不会读取到旧文件

    前端服务在静态文件路径同时反代生产和灰度环境,proxy_next_upstream http_404 ,生产 404 就读灰度,然后把结果缓存并返回
    laev
        4
    laev  
    OP
       9 天前
    @eason1874 明白了,十分感谢!我一直以来走进死胡同了。。感觉自己有点蠢[笑哭]
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2637 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 13:14 · PVG 21:14 · LAX 05:14 · JFK 08:14
    ♥ Do have faith in what you're doing.