文章目錄
-
- 背景
- SSE
- WebSocket
- 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
WebSocket
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是一個單向推送,适合像推送伺服器時間的這種簡單場景。