如何在Nginx Stream上下文用Lua修改TCP/UDP流量响应?
在NGINX Stream上下文用Lua修改TCP/UDP双向流量(请求+响应)
问题分析
你之前的配置无法生效的核心原因有两个:
preread_by_lua_block仅能读取客户端请求的前置数据,无法修改后转发给后端,且ngx.req.set_body_data是HTTP上下文专属指令,Stream环境不支持。- 该配置完全没有处理后端返回的响应数据,自然无法实现修改响应的需求。
Stream上下文没有HTTP环境中的header_filter_by_lua/body_filter_by_lua这类专门的流量过滤指令,要实现双向流量修改,需要手动接管整个连接的转发逻辑。
解决方案:手动接管双向连接并修改流量
以下是可直接使用的配置示例,通过Lua协程实现客户端与后端的双向流量转发,并在转发过程中修改请求和响应数据:
stream { server { listen 12345; content_by_lua_block { -- 获取客户端Socket(开启非阻塞模式) local client_sock = ngx.req.socket(true) if not client_sock then ngx.log(ngx.ERR, "Failed to get client socket") return end -- 建立与后端服务器的连接 local backend_sock = ngx.socket.tcp() backend_sock:settimeout(10000) -- 设置10秒超时 local ok, err = backend_sock:connect("10.0.0.1", 567) if not ok then ngx.log(ngx.ERR, "Failed to connect to backend: ", err) client_sock:close() return end -- 客户端→后端:转发并修改请求数据 local function forward_client_to_backend() while true do -- 按4096字节块读取客户端数据 local data, err, partial = client_sock:receive(4096) if not data then if err == "closed" then break end ngx.log(ngx.ERR, "Failed to read from client: ", err) break end -- 修改请求内容(替换示例) local modified_data = string.gsub(data, "old_text", "new_text") local bytes_sent, send_err = backend_sock:send(modified_data) if not bytes_sent then ngx.log(ngx.ERR, "Failed to send to backend: ", send_err) break end end backend_sock:close() client_sock:close() end -- 后端→客户端:转发并修改响应数据 local function forward_backend_to_client() while true do -- 按4096字节块读取后端响应 local data, err, partial = backend_sock:receive(4096) if not data then if err == "closed" then break end ngx.log(ngx.ERR, "Failed to read from backend: ", err) break end -- 修改响应内容(替换示例) local modified_data = string.gsub(data, "old_response_text", "new_response_text") local bytes_sent, send_err = client_sock:send(modified_data) if not bytes_sent then ngx.log(ngx.ERR, "Failed to send to client: ", send_err) break end end client_sock:close() backend_sock:close() end -- 启动协程同时处理双向流量,避免阻塞 local client_co = ngx.thread.spawn(forward_client_to_backend) local backend_co = ngx.thread.spawn(forward_backend_to_client) -- 等待两个协程执行完毕 ngx.thread.wait(client_co, backend_co) } } }
关键说明
- 依赖模块:确保你的NGINX/OpenResty已编译
ngx_stream_lua_module(OpenResty默认包含该模块)。 - UDP适配:如果需要处理UDP流量,将
ngx.socket.tcp()替换为ngx.socket.udp(),并调整连接逻辑(UDP为无连接协议,需使用sendto/receivefrom方法)。 - 参数调整:根据业务场景修改读取块大小(4096)和超时时间(10000毫秒)。
- 错误处理:配置中包含基础的错误日志记录和连接关闭逻辑,可根据需求扩展。
内容的提问来源于stack exchange,提问作者AHmedRef
相关产品推荐
相关产品推荐

