在服務端向頁面主動推送消息的業務場景下,有長輪訓和websocket兩種思路。
springboot 和websocket使用:https://blog.csdn.net/u014203449/article/details/102902078
現在看看長輪詢:
設想一個業務場景:A用戶打開頁面,要求實時刷新數據,B用戶操作新增數據,A頁面刷新。
1.頁面
長輪詢的做法是,A用戶打開頁面,就請求一個接口,js ajax請求時設置一個超時時間,比如60s。
$.ajax({
url:'', //請求的URL
timeout : 60000, //超時時間設置,單位毫秒
type : 'get', //請求方式,get或post
data :{}, //請求所傳參數,json格式
dataType:'json',//返回的數據格式
success:function(data){ //請求成功的回調函數
alert("成功");
},
2.接口
而接口中,判斷數據是否有變化,如果有變化直接將數據返回,如果沒有變化,將線程掛起60s,60s內有變化就返回數據,無變化返回空。
線程掛起可以用sleep 或者LockSupport.park 方法將其堵塞。
3.打斷阻塞
但堵塞後如何能發現數據變化,從而返回數據呢?因爲是另一個用戶B線程進行操作導致的數據變化。
1.輪詢。可以在接口中循環sleep 幾秒,去查詢數據是否發生變化。
2.B用戶線程操作後,可以找到A用戶的長輪詢線程,然後進行打斷。A用戶線程寫個判斷打斷邏輯,如果打斷標誌爲ture,就查詢數據返回。
B線程如何找到A線程呢?可以設置一個全局線程安全集合,比如CopyOnWriteArraySet,把線程放進去。
4.下一次輪詢
而js 在接口響應後,繼續發起一次請求,監聽下一次數據的變化。
5.長輪詢案列
正好看到了Apollo配置中心,配置中心服務端如何通知客戶端配置發生了變化,這就用到了長輪詢。
裏面寫到了:
- 客戶端會發起一個Http請求到Config Service的
notifications/v2
接口,也就是NotificationControllerV2,參見RemoteConfigLongPollService - NotificationControllerV2不會立即返回結果,而是通過Spring DeferredResult把請求掛起
- 如果在60秒內沒有該客戶端關心的配置發佈,那麼會返回Http狀態碼304給客戶端
- 如果有該客戶端關心的配置發佈,NotificationControllerV2會調用DeferredResult的setResult方法,傳入有配置變化的namespace信息,同時該請求會立即返回。客戶端從返回的結果中獲取到配置變化的namespace後,會立即請求Config Service獲取該namespace的最新配置。