Nginx配合Lua实现根据body参数进行路由
文章目录
- 前言
- 一、前置条件
- 二、配置步骤
- 1.docker-compose配置文件
- 2.nginx.conf文件
- 3.lua脚本
- 3.启动测试
- 3.1 执行docker-compose up -d启动nginx
- 3.2 使用postman调用http://172.39.10.3:8080/data/handle;根据入参查看目的服务的日志,有调用日志即成功转发
前言
由于公司需求,需要根据post请求中某个字段的值进行判断调用哪个第三方接口,接口路径都是相同的,入参也相同;且属于特殊需求,在不改动代码情况下,使用nginx+lua脚本形式实现此需求
提示:以下是本篇文章正文内容,下面案例可供参考
一、前置条件
- docker-compose
- nginx镜像:fabiocicerchia/nginx-lua:latest(需使用包含lua模块的镜像)
二、配置步骤
1.docker-compose配置文件
version: '3'
services:
nginx:
image: fabiocicerchia/nginx-lua:latest
container_name: nginx
ports:
- "8080:80" # 将容器的 80 端口映射到主机的 8080 端口
volumes:
- ./conf/nginx.conf:/etc/nginx/nginx.conf # 挂载本地的 nginx.conf 到容器内部
- ./html:/usr/share/nginx/html # 挂载本地的 HTML 文件到 Nginx 默认的站点目录
- ./script:/home
2.nginx.conf文件
worker_processes 1;
error_log /var/log/nginx/error.log info;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
lua_package_path "/home/?.lua;;";
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main; # 使用 main 格式记录访问日志
sendfile on;
server {
listen 80;
server_name localhost;
location /data {
# 使用lua脚本
content_by_lua_file /home/route.lua;
}
location /api/route1 {
# 配置代理到另一台服务器的接口地址
proxy_pass http://172.39.10.22:8788/data/handle;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /api/route2 {
# 配置代理到另一台服务器的接口地址
proxy_pass http://172.39.10.22:8789/data/handle;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
3.lua脚本
-- 获取请求体数据
local function get_request_body()
ngx.req.read_body()
local body_data = ngx.req.get_body_data()
return body_data
end
-- 解析请求体数据,提取参数
local function parse_request_body(body_data)
ngx.log(ngx.INFO, "Request Body Data: ", body_data)
if not body_data then
return {}
end
local args = {}
-- 去掉请求体数据中的空白字符
body_data = body_data:gsub("%s+", "")
-- 解析 JSON 对象
if body_data:sub(1, 1) == "{" and body_data:sub(-1) == "}" then
-- 去掉开头的 "{" 和结尾的 "}"
body_data = body_data:sub(2, -2)
-- 分割键值对
for pair in body_data:gmatch('("[^"]-":%s*"[^"]-"),?') do
local key, value = pair:match('("[^"]-"):%s*"([^"]-)"')
if key and value then
-- 去掉键和值的引号
key = key:gsub('"', '')
value = value:gsub('"', '')
-- 处理嵌套的对象或数组
if value:sub(1, 1) == "{" then
value = parse_request_body("{" .. value .. "}")
elseif value:sub(1, 1) == "[" then
-- 此处处理数组,根据需要解析数组内部的元素
-- 这里简化为直接存储数组字符串
end
args[key] = value
end
end
end
return args
end
-- 根据参数值进行路由
local function route_request(args)
-- ngx.log(ngx.INFO, args)
local action = args.HospitalCode
ngx.log(ngx.INFO, action)
if action == "0001" then
ngx.exec("/api/route1") -- 内部重定向到 /api/route1
elseif action == "0002" then
ngx.exec("/api/route2") -- 内部重定向到 /api/route2
else
ngx.exit(400) -- 返回 400 错误
end
end
-- 主处理逻辑
local function main()
local body_data = get_request_body()
local args = parse_request_body(body_data)
route_request(args)
end
-- 执行主处理逻辑
main()
脚本通过手动处理 JSON 字符串以解析请求体数据,如需要API解析可以导入 cjson 模块,用于处理 JSON 数据;因fabiocicerchia/nginx-lua没有这个模块,故未使用,有需要的可以研究一下。