天天看點

【開發經驗】伺服器單向推送——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是一個單向推送,适合像推送伺服器時間的這種簡單場景。

繼續閱讀