解决 SSE 在微信浏览器中无法正常使用的问题

阅读时长 7 分钟读完

背景

在前端开发中,服务器推送技术已经成为了很常用的实现方式,其中 Server-Sent Event (SSE) 是一种基于 HTTP 的推送技术,在浏览器端能实现服务器推送数据,并通过浏览器自身的事件机制来处理推送消息。

然而,一些前端工程师在实际开发中发现,SSE 在微信浏览器中无法正常使用,这使得一些基于微信公众号进行开发的项目受到了很大的影响。

原因分析

SSE 在浏览器端的实现方式,是通过 JavaScript 中的 EventSource 对象进行实现的。但是,微信浏览器在对 EventSource 对象进行跨域请求时,会对 HTTP 头部进行限制,以增强安全性。

这个限制会导致 SSE 的请求无法获得后端传输的数据,因此 SSE 就无法正常使用。

解决方案

针对这个问题,我们可以通过 nginx 将 SSE 的请求转发到一个同域下的接口上,并加上一些 HTTP 头部来规避微信浏览器的限制。

具体步骤如下:

配置 nginx

在 nginx 配置文件中,增加以下配置:

上述配置中,/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 转发的地址。

这里,将 SSE 的请求路径改为 /sse

注意事项

  1. SSE 请求路径需要与 nginx 配置文件中的配置一致。
  2. 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

纠错
反馈

纠错反馈