背景
在前端开发中,服务器推送技术已经成为了很常用的实现方式,其中 Server-Sent Event (SSE) 是一种基于 HTTP 的推送技术,在浏览器端能实现服务器推送数据,并通过浏览器自身的事件机制来处理推送消息。
然而,一些前端工程师在实际开发中发现,SSE 在微信浏览器中无法正常使用,这使得一些基于微信公众号进行开发的项目受到了很大的影响。
原因分析
SSE 在浏览器端的实现方式,是通过 JavaScript 中的 EventSource
对象进行实现的。但是,微信浏览器在对 EventSource
对象进行跨域请求时,会对 HTTP 头部进行限制,以增强安全性。
这个限制会导致 SSE 的请求无法获得后端传输的数据,因此 SSE 就无法正常使用。
解决方案
针对这个问题,我们可以通过 nginx 将 SSE 的请求转发到一个同域下的接口上,并加上一些 HTTP 头部来规避微信浏览器的限制。
具体步骤如下:
配置 nginx
在 nginx 配置文件中,增加以下配置:
location /sse { proxy_pass http://yourdomain.com:8080/sse; proxy_set_header Connection ''; proxy_set_header Host $http_host; proxy_cache_bypass $http_upgrade; proxy_set_header Upgrade $http_upgrade; proxy_read_timeout 86400; # Increase timeout for long polling. }
上述配置中,/sse
对应了 SSE 的请求路径,http://yourdomain.com:8080/sse
则是转发的接口地址。其中,proxy_set_header Connection ''
是禁用了代理服务器和后端服务器间的 keep-alive 连接,proxy_set_header Host $http_host
则是设置了代理服务器的 Host 为当前请求的 Host(即客户端请求的 Host),proxy_set_header Upgrade $http_upgrade
是针对 HTTP/1.1 协议启用长连接保持机制,proxy_cache_bypass $http_upgrade
则是防止代理缓存,proxy_read_timeout 86400
是设置了长轮询时间为 86400 秒(24 小时)。
修改 JavaScript 代码
对于 SSE 的 JavaScript 代码,需要修改部分代码,来将 SSE 请求路径改为 nginx 转发的地址。
var source = new EventSource('/sse'); source.onmessage = function(event) { // 处理 SSE 内容 };
这里,将 SSE 的请求路径改为 /sse
。
注意事项
- SSE 请求路径需要与 nginx 配置文件中的配置一致。
- SSE 服务端需要支持 HTTP/1.1 协议的 Upgrade 请求。
示例代码
下面是一个使用了 SSE 的示例代码,针对微信浏览器无法正常使用的问题,做了修改。
-- -------------------- ---- ------- -- --- ---------- -- --- ------ - --- -------------------- ---------------- - --------------- - --------------------- -------- - - ------------ -- -------------------------------- ----------- - -- ------------- -- ------------------- - ---------------- --------- - ---- - ---------------- ------- --- - -- ------- -- --- --- ---- -- -------------- ------ ----- --------- - ----- ------ --------------------------------------- ---------------- - ------ --- ----------------------------- ----------------- -------- - - ---------------- - ----------------- ----------- - --------- -------------- - ----- ------ ----- -------------- ------- ----------- - ------- -------- ------------------ -------- - --- -------------- --------- --------- ---- ------------------------ ---- ------------------- ----- ------ ----------------- ----------- - ----------------------------------------- ----------------------------------- ------------------------------- ------------ ---------------------------- -------------- ------------ ------------ - ----------------- ---------------------------- --------------------------- - -- -------------------- ------- ---- ----------- -------- - ------------------ ------------ - --- -------------- --- ------------- ------- - --------- - --- - --------------- --- - ---------------------- ----------- ------ - ---------------- ------------------- - - ------- - -------- --------------- -------------------------- -- ------- ------- -- ------------ - - ----- ---------- -- - -------------------------- -- ----- ------- --- ------------ - - - --------------------------------- -- ------ ------- - --------- ------ ---- ------------------ ------- ------ ---------------- - -- --------------------- - -展开代码
上述代码中,/sse
是 SSE 的请求路径,在 nginx 配置文件及 JS 代码中需要保持一致。
SSE 服务端采用了一个 Servlet,并使用 AsyncContext
实现长轮询。其中,doGet()
方法中,设置了 HTTP 响应头部和异步上下文,用于获取客户端的 SSE 请求。
在 push()
方法中,处理业务逻辑,并将结果推送给处于长轮询状态的客户端。
通过这种方式,我们可以在微信浏览器下,顺利地使用 SSE 技术。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67c7de16cc0f7239cdfdd25c