最近有个需求,需要nginx根据POST参数将请求转发到不同的后端,调研后决定使用OpenResty(Nginx + Lua)作为代理服务器。
写个小Demo:
location /test {
set $target_url '';
rewrite_by_lua_block {
if "POST" == ngx.req.get_method() then
ngx.req.read_body()
local args = ngx.req.get_body_data() -- 如果要获取参数推荐使用ngx.req.get_post_args
if string.match(args, "name=\"Key\"") == nil then
ngx.var.target_url = "http://127.0.0.1:8000"
else
ngx.var.target_url = "http://127.0.0.1:8080"
end
}
proxy_pass $target_url;
}
试了下,请求被正确转发了。好像一切都很好,实际用的时候,接口返回了500,因为args
的值为nil
。
看了文档:
This function returns nil if
1. the request body has not been read,
2. the request body has been read into disk temporary files,
3. or the request body has zero size.
第一条,请求体没有被读,不知道怎么判断。第二条,请求体被读进了一个临时文件,依旧不知道怎么判断。第三条,请求体是空的,基本可以否定。
后来查到:
由于内存的限制,ngx_http_read_client_request_body()接口读取的请求体会部分或者全部写入一个临时文件中,根据请求体的大小以及相关的指令配置,请求体可能完整放置在一块连续内存中,也可能分别放置在两块不同内存中,还可能全部存在一个临时文件中,最后还可能一部分在内存,剩余部分在临时文件中。
————————————————
版权声明:本文为CSDN博主「weixin_39634022」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_39634022/article/details/111848493
猜测请求体太大被写入了临时文件,lua部分代码改为:
local filename = ngx.req.get_body_file()
if type(filename) ~= "nil" then
file = io.open(filename, "r")
for line in file:lines() do
-- 读到的格式为
-- .... name="Key"
--
-- value
if string.match(line, "name=\"Key\"") ~= nil then
file:read() -- 找到key后,先读取空行,然后再去匹配value
if string.match(string.lower(file:read()), "value") == nil then
ngx.var.target_url = "http://127.0.0.1:8000"
else
ngx.var.target_url = "http://127.0.0.1:8080"
end
break
end
end
file:close()
end
请求成功。
然后将两种方式结合起来,如果其中一种找不到就去尝试另一种。
因为对Nginx和Lua都不熟悉,以上也只是一种比较笨重的实现方式。学习后再来优化。
参考: