apisix~对sse事件流的支持~api7.ai的方案

在 APISIX 中,如果你需要关闭 Nginx 的缓冲区以支持 SSE(Server-Sent Events)的 text/event-stream 响应,确保数据能够实时流式传输到客户端,可以通过以下步骤实现。


1. 禁用 Nginx 的代理缓冲

Nginx 默认会启用代理缓冲(proxy_buffering),这会导致 SSE 数据被缓存并按块返回,而不是实时流式传输。为了禁用缓冲,需要修改 Nginx 的配置。

修改 APISIX 的 Nginx 配置文件

APISIX 是基于 Nginx 的,因此可以通过修改 APISIX 的 Nginx 配置文件来禁用缓冲。

  1. 打开 APISIX 的 Nginx 配置文件模板:

    • 文件路径通常为 /usr/local/apisix/conf/nginx.conf
    • 如果你使用了自定义的 Nginx 模板,路径可能不同。
  2. http 块中添加全局配置:

    http {
        proxy_buffering off;  # 禁用代理缓冲
        proxy_buffer_size 1k;  # 设置缓冲区大小为 1KB
        proxy_buffers 4 1k;    # 设置缓冲区数量和大小
    }
    
    • proxy_buffering off:完全禁用代理缓冲,确保数据实时传输。
    • proxy_buffer_sizeproxy_buffers:将缓冲区大小设置为较小的值(如 1KB),以减少数据分块的大小。

加到某个server下面

 server {
    listen 80;
    server_name app1.example.com;
    
    # 覆盖全局配置:关闭本server所有请求的代理缓冲
    proxy_buffering off;  # ✅ 生效层级:当前server
    }

** apisix的helm版的values.yaml配置

  nginx:
    # 支持sse的事件流协议text/event-stream,在插件中为上游显示的添加了X-Accel-Buffering为no,这时当前apisix的nginx相当于走了proxy_buffering为off的特性
    http_server_location_configuration_snippet: |
      proxy_buffering        on;
  1. 保存文件并重启 APISIX:
    apisix restart
    

2. 在路由中禁用缓冲

除了全局禁用缓冲,还可以在特定路由中禁用缓冲。通过 proxy-rewrite 插件的 disable_buffering 参数实现。

示例配置

{
    "uri": "/your-sse-endpoint",
    "plugins": {
        "proxy-rewrite": {
            "disable_buffering": true  # 禁用缓冲
        }
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "your-backend-service:80": 1
        }
    }
}
  • disable_buffering: true:确保该路由的响应数据不会被缓冲。

3. 调整 Nginx 的 chunked_transfer_encoding

确保 Nginx 启用了分块传输编码(chunked_transfer_encoding),这是 SSE 流式传输的基础。

在 Nginx 配置中添加以下内容:

http {
    chunked_transfer_encoding on;  # 启用分块传输编码
}

4. 检查后端服务的响应头

确保后端服务返回的响应头中没有 Content-Length,并且启用了分块传输编码(Transfer-Encoding: chunked)。SSE 是流式协议,响应应该是分块传输的。

检查后端服务的响应头,确保如下:

HTTP/1.1 200 OK
Content-Type: text/event-stream
Transfer-Encoding: chunked
Connection: keep-alive

如果后端服务返回了 Content-Length,Nginx 可能会根据该长度进行缓冲。


5. 使用 Lua 脚本自定义流式处理

如果以上方法仍然无法满足需求,可以通过 Lua 脚本自定义流式处理逻辑,确保数据逐字转发。

示例 Lua 脚本

local core = require("apisix.core")
local ngx = ngx

local function逐字转发()
    -- 设置响应头
    ngx.header["Content-Type"] = "text/event-stream"
    ngx.header["Cache-Control"] = "no-cache"
    ngx.header["Connection"] = "keep-alive"

    -- 连接后端服务
    local sock = ngx.socket.tcp()
    local ok, err = sock:connect("your-backend-service", 80)
    if not ok then
        core.log.error("failed to connect to backend: ", err)
        return ngx.exit(500)
    end

    -- 逐字读取并转发
    while true do
        local byte, err = sock:receive(1)  -- 每次读取 1 字节
        if not byte then
            break
        end
        ngx.print(byte)  -- 逐字转发
        ngx.flush(true)  -- 立即刷新缓冲区
    end

    -- 关闭连接
    sock:close()
end

return逐字转发

在路由中应用 Lua 脚本

通过 serverless-pre-function 插件加载 Lua 脚本:

{
    "uri": "/your-sse-endpoint",
    "plugins": {
        "serverless-pre-function": {
            "phase": "access",
            "functions": [
                "local function逐字转发 = require('sse_stream') 逐字转发()"
            ]
        }
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "your-backend-service:80": 1
        }
    }
}

6. 测试

完成配置后,通过以下方式测试 SSE 数据是否实时流式传输:

  • 使用 curl 测试:

    curl -N http://<APISIX-IP>:<APISIX-PORT>/your-sse-endpoint
    
  • 在浏览器中测试:
    打开开发者工具,查看 SSE 数据是否实时接收。


总结

要关闭 Nginx 的缓冲区以支持 SSE 的 text/event-stream 响应,可以:

  1. 在 Nginx 配置中禁用代理缓冲(proxy_buffering off)。
  2. 在路由中设置 disable_buffering: true
  3. 确保后端服务返回分块传输编码(Transfer-Encoding: chunked)。
  4. 如果需要更精细的控制,可以使用 Lua 脚本自定义流式处理逻辑。

通过这些方法,可以确保 SSE 数据实时流式传输到客户端。

posted @ 2025-03-07 14:04  张占岭  阅读(679)  评论(0)    收藏  举报