因为公司业务使用了 Server-Sent Events,在调试过程中发现服务经过 apisix 时无法响应。
问题描述:
apisix 版本: 2.11.0
chrome 浏览器访问 ✔
postman 访问 ❌
Server-Sent Events(SSE)是一种用于通过单向通信从服务器向客户端发送实时更新的网络技术。它建立在传统的基于 HTTP 的通信之上,但与传统的 HTTP 请求 - 响应模型不同,SSE 允许服务器主动向客户端推送数据,而不需要客户端显式发起请求。
SSE 主要用于实现服务器到客户端的单向实时通信,比如推送实时事件、通知、更新等。与 WebSocket 相比,SSE 更简单,因为它只需要使用标准的 HTTP 协议,而不需要建立全双工的套接字连接。
SSE 的基本工作流程如下:
- 客户端通过标准的 HTTP 请求(GET 请求)向服务器请求一个特殊的端点,这个端点通常以 “.sse” 或 “.events” 结尾,以表示支持 SSE。
- 一旦服务器收到 SSE 请求,它会发送一个初始的 HTTP 响应,并在响应头中包含 “Content-Type: text/event-stream”,表示这是一个 SSE 连接。
- 服务器保持响应保持打开状态,随时可以向客户端发送新的数据。服务器可以周期性地发送数据,每个数据块被称为一个事件(event)。
- 客户端通过在 JavaScript 中使用 EventSource API 来监听这些事件。当服务器发送新事件时,客户端会触发相应的事件处理程序,从而处理更新的数据。
经过排查确定 apisix 代理会根据业务返回 Header 来确定是否对内容进行缓存。
相关问题解决: https://stackoverflow.com/questions/46371939/sse-over-https-not-working
解决方法:
# 服务返回内容 header 中设置 X -Accel-Buffering
response.headers['X-Accel-Buffering'] = 'no'
X-Accel-Buffering
设置此连接的代理缓存,将此设置为 no
将允许适用于 Comet
和HTTP
流式应用程序的无缓冲响应。将此设置为 yes
将允许响应被缓存。默认yes
。
大家调试过程中可以使用自己编译的测试程序对 sse 服务进行调试。
这里我用 golang 根据 gin 官方示例修改的 sse 测试服务器,大家可以自行测试
docker run -itd -p 8085:8085 typ431127/sse-server:0.1
部署后访问 http:// 部署 IP:8085 http 页面
http:// 部署 IP:8085/stream sse 服务测试程序
经过测试在 apisix 上使用 response-rewrite 设置 header 是无法解决这个问题的,建议大家还是在服务上面返回 X -Accel-Buffering header 信息
golang 中的设置
c.Writer.Header().Set("X-Accel-Buffering", "no")