一、背景说明
准备在项目中基于nginx、OpenResty搭建一个简易网关,实现同一域名根据不同cookie代理不同docker功能,降低前端、移动端多业务线并行测试联调成本。简单来说就是服务端有多个测试环境docker分别部署不同业务需求代码,通过在前端、移动端种植cookie(存放服务端测试环境docker IP地址)方式让其具有可选择服务端测试环境能力,大大降低联调环境配置成本。具体cookie的解析逻辑在nginx中使用lua实现。
二、lua中读写header、cookie 代码
---获取请求header
local reqHeaders = ngx.req.get_headers();
---获取请求cookie
local reqCookie = reqHeaders["cookie"];
--读取cookie值
local pcip = ngx.var.cookie_pcip;
pcip=reqCookie["pcip"];
--设置赋值cookie
ngx.header['Set-Cookie']={"pcip=127.0.0.1;domain=.timer.com;path=/" }
注:在nginx.header['Set-Cookie'] 时遇到一个问题,一次性种植多个cookie时,会出现无法一次性全部种植成功的情况,需要多次请求种植方能全部种植成功,在实战中请慎用。尤其在ngx.say()方法调用之前种植cookie出现无法一次种植成功现象几率大,在ngx.print()方法调用之前种植cookie也会如此。
其他辅助代码:
--获取请求URI
local requestUri = ngx.var.request_uri;
--获取请求域名
local requestHost = ngx.var.host;
----获取请求方法类型GET POST
local reqType= ngx.var.request_method;
--打印日志
ngx.log(ngx.ERR, ',requestHost:'..requestHost);
--反馈客户端信息
ngx.print("反馈输出纯文本");
ngx.say("反馈输出页面");
三、lua 脚本中嵌入 resty.http 文件,在lua中借助于resty.http代理http请求
resty.http (http.lua和http_headers.lua)文件下载地址:https://github.com/ledgetech/lua-resty-http/tree/master/lib/resty
--引入resty.http文件
package.path = package.path..';/export/Instances/timer/lua/resty/?.lua;'
local myHttp = require "http"
---Get 请求
local function http_get(url,headerParm,timeout)
local httpc = myHttp.new();
timeout = timeout or 30000;
httpc:set_timeout(timeout)
local res, err_ = httpc:request_uri(url, {
method = "GET",
keepalive=false,
headers = headerParm;
})
httpc:set_keepalive(5000, 100);
---httpc:close();
return res,err_;
end
---Post 请求
local function http_post(url,headerParm,body,timeout)
local httpc = myHttp.new();
timeout = timeout or 30000;
httpc:set_timeout(timeout);
local res, err_ = httpc:request_uri(url, {
method = "POST",
body = body,
keepalive=false,
headers = headerParm;
})
httpc:set_keepalive(5000, 100)
---httpc:close();
return res,err_;
end
在lua脚本中根据请求类型代理Http请求:
---请求路径
local reqUrl ="代理的请求URL地址";
----请求类型
local reqType= ngx.var.request_method;
--读取reqResult返回结果中的header 信息,赋值给nginx的Response header中
local function setResHeader(res)
if(res ~= nil)then
for k,v in pairs(res.headers) do
ngx.header[k]=v;
end
end
end
if reqType == 'POST' then
ngx.req.read_body();
local reqBody = ngx.req.get_body_data();
local reqResult,reqErr = http_post(reqUrl,reqHeaders,reqBody,30000);
ngx.status = reqResult.status;
setResHeader(reqResult);
if(reqResult.status==200) then
--返回200 code码时直接将结果返回
ngx.say(reqResult.body);
return ;
elseif(reqResult.status==302) then
--返回302 重定向时 需要将重定向url 赋值到response 的header.Location中
ngx.header.Location=reqResult.headers.location;
return ;
else
--报错处理
if reqErr == nil then
reqErr="";
end
ngx.say(reqResult.status..":"..reqErr);
return ;
end
else
local reqResult,reqErr = http_get(reqUrl,reqHeaders,30000);
ngx.status = reqResult.status;
setResHeader(reqResult);
if(reqResult.status==200) then
ngx.say(reqResult.body);
return ;
elseif(reqResult.status==302) then
ngx.header.Location=reqResult.headers.location;
return ;
else
if reqErr == nil then
reqErr="";
end
ngx.say(reqResult.status..":"..reqErr);
return ;
end
end
四、nginx 引入lua脚本
server {
listen 80;
server_name www.timer.com;
access_log /export/servers/nginx/logs/nginx_access.log realaddr;
error_log /export/Logs/nginx_errr.log warn;
root /export/Instances/timer/runtime/;
index index.html;
charset utf-8;
location / {
#default_type 'text/html'; 返回HTML页面
default_type 'application/json'; #返回Json文本
charset utf-8;
lua_code_cache off;
#加载引入lua脚本
content_by_lua_file /export/Instances/timer/runtime/lua/gateway.lua;
}
}
注:使用access_by_lua_file加载lua脚本会出现间接性404问题:https://blog.csdn.net/TimerBin/article/details/103850392
五、其他资料
resty-http帮助文档: https://github.com/ledgetech/lua-resty-http#request