一、背景說明
準備在項目中基於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