天天看点

【开发经验】服务器单向推送——SSE

文章目录

    • 背景
    • SSE
    • WebSocket
    • SSE实现时间下发功能
    • 代码实现

背景

        目前广州疫情,每次出行都需要出示健康码,有的小伙伴比较机智,为了更加快速的通行,对于健康码进行截图,这样就可以很快的打开健康码。但是这样也违背了地铁查看健康码的初衷,很可能存在有的人黄码,然后找朋友的绿码出行。

        为了防止这一情况。检查人员需要看到健康码的时间是变化的,才放行。

【开发经验】服务器单向推送——SSE

如上图时间,在网络正常的时候,时间会实时变化,断开网络之后,网络会卡住。这个时间肯定是服务器时间。因为如果是本地时间,可以通过修改自己手机时间进行修改。

问题来了,联网变化,断网暂定,这个功能如何实现呢?脑回路中迅速转动后得出如下结论

  • ajax轮询,每隔一段时间就请求一次服务器,然后更新页面的时间。
  • websocket推送,可以建立长连接,然后通过服务器进行推送。
  • SSE单向推送。

        这种情况,笔者以为ajax轮询的方式很鸡肋,当然压力小的情况下,简单的做一个小功能还是可以的;websocket只是推送一个服务器时间,未免有点太重量级了。因此,这个场景非常适合SSE的使用。

        Server-sent Events(sse)与长轮询机制类似,区别是每个连接不只发送一个消息。客户端发送一个请求,服务端保持这个连接直到有新消息发送回客户端,仍然保持着连接,这样连接就可以消息的再次发送,由服务器单向发送给客户端。

        SSE本质是发送的不是一次性的数据包,而是一个数据流。可以使用 HTTP 301 和 307 重定向与正常的 HTTP 请求一样。服务端连续不断的发送,客户端不会关闭连接,如果连接断开,浏览器会尝试重新连接。如果连接被关闭,客户端可以被告知使用 HTTP 204 无内容响应代码停止重新连接。

        sse只适用于高级浏览器,ie不支持。因为ie上的XMLHttpRequest对象不支持获取部分的响应内容,只有在响应完成之后才能获取其内容。

        这时SSE与WebSocket的区别可以简单的认为,SSE是单向服务器推送到客户端,WebSocket是双工通信。

SSE

【开发经验】服务器单向推送——SSE

WebSocket

【开发经验】服务器单向推送——SSE

SSE实现时间下发功能

【开发经验】服务器单向推送——SSE

代码实现

一个简单的springboot工程

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.10.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
           

新建controller

@Slf4j
@RestController
public class SSEController
{
   @GetMapping ("/stream-sse-mvc")
   public SseEmitter streamSseMvc() {
      SseEmitter emitter = new SseEmitter();
 
      ExecutorService sseMvcExecutor = Executors.newSingleThreadExecutor();
      sseMvcExecutor.execute(() -> {
         try {
            for (int i = 0; i<10; i++) {
               SseEmitter.SseEventBuilder event = SseEmitter.event()
                     .data("我是一个data现在的时间是" + LocalTime.now().toString());
//                   .id(String.valueOf(i))
//                   .name("sse event - mvc");
               emitter.send(event);
               Thread.sleep(1000);
            }
         } catch (Exception ex) {
            emitter.completeWithError(ex);
         }
      });
      return emitter;
   }
}
           

        浏览器请求该controller即可。真实场景,如果汉字乱码在请求头添加

Content-Type: text/event-stream;charset=UTF-8

即可。

此功能为,每个一秒,返回服务器时间。

SSE是一个单向推送,适合像推送服务器时间的这种简单场景。

继续阅读