应用场景:
用户请求想要生产的流量打到原有服务的同时,打到新开发的服务上试一下
注意的点:
1 nginx是不读请求体的,需要在配置文件中打开,或者读取前调用ngx.req.read_body(),然后通过local data = ngx.req.get_body_data()获取
2 header转发时如果原请求里有"accept-encoding"这样支持压缩的声明返回的是二进制,记录日志不方便读取要单独处理下
Lua
-- mirror.lua
local core = require("apisix.core")
local http = require("resty.http")
local json = require("apisix.core.json")
local plugin_name = "mirror"
local schema = {
type = "object",
properties = {
uri = {
type = "string",
},
serviceHost = {
type = "string",
},
serviceName = {
type = "string",
},
method = {
type = "string",
enum = {"POST", "GET"},
default = "POST"
},
timeout = {
type = "number",
default = 3000
},
},
}
local _M = {
version = 0.1,
priority = 98,
name = plugin_name,
schema = schema,
}
function _M.check_schema(conf)
local ok, err
ok, err = core.schema.check(schema, conf)
if not ok then
return false, err
end
if not conf.serviceHost then
conf.serviceHost = conf.serviceName
end
if conf.timeout < 0 then
conf.timeout = 5 * 1000
end
return true
end
-- timeout in ms
local function http_req(method, uri, body, myheaders, timeout)
local httpc = http.new()
if timeout then
httpc:set_timeout(timeout)
end
myheaders["accept-encoding"] = nil
core.log.info("Mirrored request http uri ", uri," method ", method)
core.log.info("Mirrored request http header ", core.json.delay_encode(myheaders))
core.log.info("Mirrored request http req param ", core.json.delay_encode(body))
local res, err = httpc:request_uri(uri, {
method = method,
body = body,
headers = myheaders,
ssl_verify = false
})
core.log.info("Mirrored request http status ", res.status)
core.log.info("Mirrored request http body ", res.body)
return res
end
function _M.access(conf, ctx)
core.log.info("Mirrored request start ")
ngx.req.read_body()
local data = ngx.req.get_body_data()
local req_headers = ngx.req.get_headers()
req_headers["Host"] = conf.servicHost
core.log.info("Mirrored request conf ", core.json.delay_encode(conf))
local method = conf.method
if not method or method == nil or method == "" then
method = ngx.req.get_method()
end
local url = conf.serviceName
if not conf.uri or conf.uri == nil or conf.uri == "" then
url = url .. ngx.var.uri
else
url = url .. conf.uri
end
local args, err = ngx.req.get_uri_args()
if G then
local first = true
for key, val in pairs(args) do
if first then
url = url .. "?"
first = false
else
url = url .. "&"
end
url = url .. key .. "=" .. val
end
end
local res,err = http_req(method, url, data, req_headers, conf.timeout)
core.log.info("Mirrored request end")
end
return _M