NGINX - OpenResty - 如何根据字符串反向代理对两个不同服务器的调用?

NGINX - OpenResty - 如何根据字符串反向代理对两个不同服务器的调用?

我正在尝试配置 NGINX/OpenResty,以根据 SOAP 请求中存在的字符串将 SOAP 调用代理到 ​​2 个不同的服务器。

我能做什么:我能够根据 SOAP 客户端调用的路径将请求代理到 2 个不同的服务器:

location /pathA {
    proxy_pass http://www.ServerA.com/PathA/;
}
location /pathB {
    proxy_pass http://www.ServerB.com/PathB/;
}

我不能做的事:

我无法根据请求的内容分离流量。我认为主要原因是我无法正确组装 LUA 脚本来提取信息并随后使用它来代理请求。

location / {
    conten_by_lua '
        ngx.req.read_body()
        local match = ngx.re.match(ngx.var.request_body,"STRING TO FIND")
        if match then
            proxy_pass http://www.ServerA.com/PathA/;
        else
            proxy_pass http://www.ServerB.com/PathB/;

我怎样才能做到这一点?

我安装了 OpenResty 并且 LUA 运行良好。

我记得我读到过一篇文章,如果请求不是 HTTP POST,则ngx.req.read_body()无法工作。对吗?

感谢您的帮助。

答案1

您几乎自己做到了,我唯一会做的不同的事情就是使用rewrite_by_lua而不是content_by_lua

location / {
    set $proxy "";
    rewrite_by_lua '
        ngx.req.read_body()
        local match = ngx.re.match(ngx.var.request_body, "STRING TO FIND")
        if match then
            ngx.var.proxy = "www.ServerA.com"
        else
            ngx.var.proxy = "www.ServerB.com"
        end
    ';
    proxy_pass http://$proxy$uri;
}

如果请求不是 HTTP POST 或具有空主体,ngx.req.read_body()将返回nil,因此最好添加额外的检查:

location / {
    set $proxy "";
    rewrite_by_lua '
        ngx.req.read_body()
        local body = ngx.var.request_body
        if (body) then
            local match = ngx.re.match(body, "STRING TO FIND")
            if match then
                ngx.var.proxy = "www.ServerA.com"
            else
                ngx.var.proxy = "www.ServerB.com"
            end
        else
            ngx.status = ngx.HTTP_NOT_FOUND
            ngx.exit(ngx.status)
        end
    ';
    proxy_pass http://$proxy$uri;
}

您还可以限制允许的方法:

location / {
    limit_except POST { deny all; }
    ...
}

还有一件事。使用此配置,如果您使用域名而不是 IP 地址指定后端,则需要resolver指令。您可以使用本地名称服务器(如果有),或者使用外部服务器,例如 Google 公共 DNS(8.8.8.8)或 ISP 为您提供的 DNS。

答案2

下面是我在 openresty 中用来根据发布的 json 主体区分 dev 和 prod webhook 的代码片段:

server {
    listen 8080;
    resolver 114.114.114.114 8.8.8.8 valid=30s;

    location /webhook {
        limit_except POST { deny all; }

        set $proxy "";

        rewrite_by_lua_block {
            local devWebhook = "myservice.dev"   -- todo
            local prodWebhook = "mysevice.prod" -- todo

            function getFile(file_name)
                local f = assert(io.open(file_name, 'r'))
                local string = f:read("*all")
                f:close()
                return string
            end

            ngx.req.read_body()
            local data = ngx.req.get_body_data()
            if nil == data then
                local file_name = ngx.req.get_body_file()
                if file_name then
                    data = getFile(file_name)
                end
            end

            local json = require("cjson.safe")
            local t    = json.decode(data)
            if not (type(t) == "table" and t["msg"]) then
                ngx.exit(400)
            end               

            local msg = ngx.unescape_uri(t["msg"])
            if not (type(msg) == "string" and #msg > 0) then
                ngx.exit(400)
            end

            if string.find(msg, '"title":".*test product.*"') then
                ngx.var.proxy = devWebhook
            else
                ngx.var.proxy = prodWebhook
            end
        }

        proxy_pass http://$proxy$uri;
    }
}

相关内容