You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Nginx Stream上下文用Lua修改TCP/UDP流量响应?

在NGINX Stream上下文用Lua修改TCP/UDP双向流量(请求+响应)

问题分析

你之前的配置无法生效的核心原因有两个:

  1. preread_by_lua_block仅能读取客户端请求的前置数据,无法修改后转发给后端,且ngx.req.set_body_data是HTTP上下文专属指令,Stream环境不支持。
  2. 该配置完全没有处理后端返回的响应数据,自然无法实现修改响应的需求。

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)
        }
    }
}

关键说明

  1. 依赖模块:确保你的NGINX/OpenResty已编译ngx_stream_lua_module(OpenResty默认包含该模块)。
  2. UDP适配:如果需要处理UDP流量,将ngx.socket.tcp()替换为ngx.socket.udp(),并调整连接逻辑(UDP为无连接协议,需使用sendto/receivefrom方法)。
  3. 参数调整:根据业务场景修改读取块大小(4096)和超时时间(10000毫秒)。
  4. 错误处理:配置中包含基础的错误日志记录和连接关闭逻辑,可根据需求扩展。

内容的提问来源于stack exchange,提问作者AHmedRef

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:10:09