apisix~对sse事件流的支持~api7.ai的方案
-
企业级中有proxy-buffer插件,说是可以支持sse
-
https://docs.api7.ai/hub/proxy-buffering
-
https://github.com/apache/apisix/issues/11977
-
https://github.com/apache/apisix/issues/10204
在 APISIX 中,如果你需要关闭 Nginx 的缓冲区以支持 SSE(Server-Sent Events)的 text/event-stream
响应,确保数据能够实时流式传输到客户端,可以通过以下步骤实现。
1. 禁用 Nginx 的代理缓冲
Nginx 默认会启用代理缓冲(proxy_buffering
),这会导致 SSE 数据被缓存并按块返回,而不是实时流式传输。为了禁用缓冲,需要修改 Nginx 的配置。
修改 APISIX 的 Nginx 配置文件
APISIX 是基于 Nginx 的,因此可以通过修改 APISIX 的 Nginx 配置文件来禁用缓冲。
-
打开 APISIX 的 Nginx 配置文件模板:
- 文件路径通常为
/usr/local/apisix/conf/nginx.conf
。 - 如果你使用了自定义的 Nginx 模板,路径可能不同。
- 文件路径通常为
-
在
http
块中添加全局配置:http { proxy_buffering off; # 禁用代理缓冲 proxy_buffer_size 1k; # 设置缓冲区大小为 1KB proxy_buffers 4 1k; # 设置缓冲区数量和大小 }
proxy_buffering off
:完全禁用代理缓冲,确保数据实时传输。proxy_buffer_size
和proxy_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;
- 保存文件并重启 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
响应,可以:
- 在 Nginx 配置中禁用代理缓冲(
proxy_buffering off
)。 - 在路由中设置
disable_buffering: true
。 - 确保后端服务返回分块传输编码(
Transfer-Encoding: chunked
)。 - 如果需要更精细的控制,可以使用 Lua 脚本自定义流式处理逻辑。
通过这些方法,可以确保 SSE 数据实时流式传输到客户端。