nginx根据post请求体内容转发

因为nginx自带的$request_body最早是在content阶段读取,uri已经确定,无法用if等判断进行重新转发,故使用nginx+lua实现,使用lua在rewrite阶段把请求体读出来,然后写脚本判断,进行转发。
代码示例如下:

--- nginx根据请求体参数转发,POST请求体最早在rewrite阶段读取
--- rewrite_by_lua_block{}

local fw_check_key = "myKey"
local values_table = { "aa", "bb", "cc" }
local ng_forward_pre = "/forward_by_lua"

--local fw_check_re_kv = [["myKey":"[^"]*"]]
local fw_check_re_kv = "\"" .. fw_check_key .. "\":\"[^\"]*\""
local l_offset = #fw_check_key + 4
local r_offset = -1
local values_table_kv = {}
local re_find = ngx.re.find
local sub = string.sub

local _M = {
    _VERSION = "0.0.1"
}
_M.__index = _M

function _M.init()
    local self = setmetatable({}, _M)
    for _, v in pairs(values_table) do
        values_table_kv[v] = true
    end
    return self
end

local function err_log(...)
    ngx.log(ngx.ERR, "fw-by-args-rw: ", ...)
end
local function warn_log(...)
    ngx.log(ngx.WARN, "fw-by-args-rw: ", ...)
end
local function exec()
    local forward_uri = ng_forward_pre .. ngx.var.uri
    local query_string = ngx.var.query_string
    if query_string then
        forward_uri = forward_uri .. "?" .. query_string
    end
    return ngx.exec(forward_uri)
end

function _M:forward_by_args()
    local req_method = ngx.var.request_method
    if req_method == "GET" then
        local args, err = ngx.req.get_uri_args()
        if not args then
            err_log("failed to get args: ", err)
            return
        end
        local key = args[fw_check_key]
        if values_table_kv[key] then
            return exec()
        end
    elseif req_method == "POST" then
        ngx.req.read_body()
        local args, err = ngx.req.get_post_args()
        if not args or type(args) ~= "table" then
            err_log("failed to get args: ", err)
            return
        end
        local key = args[fw_check_key]
        if values_table_kv[key] then
            return exec()
        end
        --可能请求体都在key,val为true
        for key, val in pairs(args) do
            if type(val) == "boolean" then
                local from, to, err = re_find(key, fw_check_re_kv, "jo")
                if err or not from then
                    warn_log("re_find error:", err)
                else
                    key = sub(key, from + l_offset, to + r_offset)
                    if values_table_kv[key] then
                        return exec()
                    end
                end
            end
        end
    else
        err_log("request method not match: ", ngx.var.request_method, ngx.var.uri)
    end
end

return _M


使用方法:
①http下增加

init_by_lua_block{
		require("forward_by_args_rewrite").init()
}

②对应接口的location下增加

rewrite_by_lua_block{
        require("forward_by_args_rewrite"):forward_by_args()
}

③增加一个新的location,appid匹配成功的会转到这里(proxy_pass最后要加斜杠)

location  /forward_by_lua/ {
		 ……
         proxy_pass xxxx/;
}

你可能感兴趣的:(nginx,nginx,lua,运维)