一、背景说明
准备在项目中基于nginx搭建一个简易网关,实现同一域名根据不同cookie代理不同docker功能,降低前端、移动端多业务线并行测试联调成本。简单来说就是服务端有多个测试环境docker分别部署不同业务需求代码,通过在前端、移动端种植cookie(存放服务端测试环境docker IP地址)方式让其具有可选择服务端测试环境能力,大大降低联调环境配置成本。具体cookie的解析逻辑在nginx中使用lua实现。
二、问题说明
根据相应nginx+lua资料配置后,一切顺利,可正常访问。但是在配合前端、移动端研发人员进行联调时,间接频繁出现请求404情况,同一接口请求参数相同,请求时间段不同,会间接出现404报错情况,在出现404时,nginx中报错信息如下所示:
2020/01/02 17:16:51 [error] 506478#0: *2183 open() "/export/Instances/Logs/runtime/api/timer/info" failed (2: No such file or directory), client: xx.xx.xx.xx, server: www.timer.com, request: "GET" .......
从错误信息来看出现404报错时,请求是直接在nginx中找静态文件的反向代理了。我有在lua脚本中打印了执行日志信息,在出现404错误时,lua脚本正常执行成功。由于该问题间接性出现,大大增加了问题排查的难度。
三、解决方案
先说解决方案,修改nginx 中lua脚本导入方式,详细如下所示:
错误方式(会出现404):
location / {
default_type 'application/json';
charset utf-8;
lua_code_cache on;
access_by_lua_file /export/Instances/timer/runtime/lua/timer.lua;
}
正确方式:
location / {
default_type 'application/json';
charset utf-8;
lua_code_cache on;
content_by_lua_file /export/Instances/timer/runtime/lua/timer.lua;
}
access_by_lua:在请求访问阶段处理,用于访问控制,适用于http、server、location、location if
content_by_lua:是内容处理器,接受请求并输出响应,适用于location、location if
注:我的解决方案是试出来的,由于access_by_lua 和 content_by_lua 资料相对较少,至于最根本的原因,我还没弄明白
四、排查与总结笔记
1、前期考虑是由于配置了 lua_code_cache on ,导致lua脚本被缓存导致的,深入学习了一下,非问题根本原因。
lua_code_cache :启用或禁用指令中Lua代码的Lua代码缓存。关闭时,ngx_lua提供的每个请求都将在一个单独的Lua VM实例中运行,引用的Lua文件将不被缓存,所有使用的Lua模块都将从头开始加载;开启时,lua脚本会被缓存,需要reload nginx才能让更新后的lua脚本生效
2、考虑是lua脚本错误导致的,在lua脚本本中打印了诸多日志,最后发现出现404错误时,lua脚本可正常执行,输出日志信息
记录常用命令:
---请求header
local reqHeaders = ngx.req.get_headers();
----请求类型
local reqType= ngx.var.request_method;
---请求cookie
local reqCookie = reqHeaders["cookie"];
local pcIp = ngx.var.cookie_pcip;
local appIp = ngx.var.cookie_appip;
--请求URL
local requestUri = ngx.var.request_uri;
--请求域名地址
local requestHost = ngx.var.host;
五、未完待续
继续查找 access_by_lua 和 content_by_lua 配置的相关资料
以上问题中lua 返回代码如下所示:
local timerHttp = require "resty.http"
---Post 请求
local function http_post(url,headerParm,body,timeout)
local httpc = timerHttp.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)
return res,err_;
end
local reqResult,reqErr = http_post(nowUrl,reqHeaders,reqBody,30000);
if(reqResult.status==200) then
ngx.say(reqResult.body);
return ;
else
ngx.say(reqErr);
return ;
end