利用ajax長輪詢、短輪詢實現消息實時更新

前言

    實現消息實時更新常見的三種方式是:短輪詢、長輪詢和websocket。短輪詢、長輪詢是http輪詢機制,利用瀏覽器持續發送請求,服務器將最新的數據響應請求,本質還是http協議的request-response模式。websocket利用了http協議完成一部分握手過程,首先發起http請求,在請求頭中加入升級爲websocket的必要參數,服務器收到請求便不再走http協議,而是創建並保持一個websocket連接,返回確認信息給瀏覽器。

    簡單來說,輪詢是瀏覽器主動請求最新數據,websocket是服務器主動推送最新數據。

    http請求中,最常用的是ajax異步請求,所以ajax輪詢實際上就是http輪詢,只是請求的方法指定爲ajax。

    實現消息實時更新還有一種方式:Comet,一般有兩種實現方式:http長輪詢、基於 Iframe 及 htmlfile 的流方式。流方式實際是利用iframe創建一個隱藏的src組件,使用http長連接的方式。

    http2.0中有一個服務器推送的概念,與上述實現comet的流方式概念不同。http2.0的服務器推送簡單來說可以爲:一次請求多次響應。舉個栗子,用戶請求一個html頁面時,在http1.x版本,流程將是:請求html—返回html—請求css—返回css—請求js—返回js…,也就是一個html頁面會有多次請求多次響應。而http2.0使用服務器推送時,流程將可以是:請求html—返回html—返回css—返回js…節省了多次請求的資源和時間。

一、http長連接和短連接

    HTTP長連接(long connection)與短連接(short connection)本質上是TCP長連接和短連接。短連接是最常見的連接類型,在完成一次HTTP請求和響應後馬上斷開TCP連接,下次請求將重建一個新的TCP連接。而長連接則指請求響應後不立刻斷開TCP連接,下次請求將複用該TCP連接,直至超時斷開。HTTP/1.0默認短連接,HTTP/1.1起默認長連接,長連接通過在請求頭設置Connection: keep-alive啓用、通過Keep-Alive: timeout=20設置長連接的超時時間(秒)。

相同點 不同點
HTTP長連接 都是基於TCP連接,並無本質不同;由HTTP請求頭Connection: keep-alive控制是否長/短連接。 1、使用次數:重用多次;2、關閉時機:超時後才關閉該TCP連接,由Keep-Alive: timeout=20控制超時時間(秒)。
HTTP短連接 1、使用次數:僅使用一次;2、關閉時機:一次HTTP請求響應後立即關閉該TCP連接。

二、http長輪詢和短輪詢

    http長輪詢(long polling):服務端收到請求後若有數據立即返回,若無數據則保持到有數據或一段時間後超時,瀏覽器收到響應後立即重新發送相同的請求;

    http短輪詢(short polling):服務端收到請求後無論是否有數據都立即返回,瀏覽器收到響應後間隔一段時間後重新發送相同的請求。

    http長輪詢/短輪詢和http長連接/短連接沒有必然關係。長輪詢未必要使用長連接,使用了長連接也未必是使用長輪詢。

相同點 不同點
HTTP長輪詢 都是基於HTTP連接,都將重複發送相同請求。 1、請求發送頻率:瀏覽器端收到HTTP響應後立即重複發起相同HTTP請求;2、服務器端處理機制:有數據時立即響應,無數據時等待數據或直到超時;3、特點:獲取數據比較實時,服務器端需要較多資源以維持衆多長輪詢。
HTTP短輪詢 1、請求發送頻率:瀏覽器端收到HTTP響應後間隔一段自定義時間後重複發起相同HTTP請求;2、服務器端處理機制:無論是否有數據都立即響應;3、特點:獲取數據不實時,通過瀏覽器端腳本即可實現。

在這裏插入圖片描述

三、長輪詢、短輪詢和websocket優缺點的簡單對比

短輪詢

    優點:實現簡單,瀏覽器使用循環不斷地、間隔地發送請求獲取數據即可。

    缺點:頻繁創建/斷開連接,每次請求都會查詢一遍數據不管有無都返回,對服務器業務處理的性能有很大的需求和壓力;因爲請求間有間隔時間,獲取的數據是僞實時的,不適應對實時性要求很高的項目。

長輪詢

    優點:有數據/超時纔會響應,收到響應後馬上發送請求,相比短輪詢減少連接的創建/斷開,獲取的數據實時性更強(間隔時間只是一個RTT,一般不會很長)。

    缺點:對服務器的併發處理性能有很大的需求和壓力;由於在返回數據前可能會有一定的等待時間,那麼需要維持着一個空閒的tcp連接。

輪詢都有共同的缺點:佔用很多資源,併發量一多起來容易崩;其次必須由瀏覽器主動去請求,服務器不會主動告知最新數據。

websocket

    優點:只要建立websocket連接,服務器主動推送最新的數據,不需要瀏覽器發送請求(其實還是要發請求建立連接,不過只需一次);實時性最優越;創建連接所耗費的資源相對較少,因爲一次請求就維持連接,不用頻繁解析http請求。

    缺點:利用到tcp長連接,爲維持長連接所耗費的資源也同樣不少,且連接的利用率實際上也是不高的;

    難點:斷線重連問題,如何保證每次數據只會推一遍而不會重複推送;單生產多消費問題(多頁面重開問題),一次數據怎麼推送給多個用戶,如果每個頁面都創建一個websocket,那麼資源耗費太多;

四、利用ajax實現長輪詢和短輪詢

4.1 簡單實現

前端測試頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax長輪詢和短輪詢</title>
</head>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">

    // 使用定時器實現短輪詢
    function shortPolling() {
        setInterval(shortAjax,5000);
    }

    function shortAjax() {
        $.ajax({
            type:"get",
            url:"/javatest/student/findOneShort/" + 10001,
            dataType:"json",
            success:function(result) {
                var msg = $("#message").html() + result.id+':'+result.name+'='+result.score+'\n';
                $("#message").html(msg);
            },
            timeout:10000,  //測試超時10s會不會報錯,實際可以調大一點
            error:function (error) {
                console.log("ajax執行失敗");
            }
        })
    }

    // 長輪詢
    function longPolling() {
        $.ajax({
            type:"get",
            url:"/javatest/student/findOneLong/" + 10001,
            dataType:"json",
            success:function(result) {
                var msg = $("#message").html() + result.id+':'+result.name+'='+result.score+'\n';
                $("#message").html(msg);
                longPolling();     // 正常獲取數據馬上發起新請求
            },
            timeout:15000,  //測試超時15s會不會報錯,實際可以調大一點
            error:function (error) {
                console.log("ajax執行失敗");
                longPolling();     // 超時或報錯則重新發起請求
            }
        })
    }
</script>
<body>
<p>【操作】:<div><input type="button" id="short" onclick="shortPolling()" value="ajax短輪詢"/><br/>
<p>【操作】:<div><input type="button" id="long" onclick="longPolling()" value="ajax長輪詢"/><br/>
<p>【接收內容】:<div><textarea id="message" rows="10" cols="30"></textarea></div>
</body>
</html>

後臺測試controller

只是爲了模擬後臺請求效果而提供的接口。輪詢主要是靠前端實現。

import com.javatest.po.StudentScore;
import com.javatest.service.StudentScoreService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/student")
public class StudentScoreController {

    @Autowired
    private StudentScoreService service;

    @GetMapping("/findOneShort/{id}")
    public StudentScore findStudentScoreByIdShort(@PathVariable("id") Long id) {
        return service.selectByPrimaryKey(id);
    }

    @GetMapping("/findOneLong/{id}")
    public StudentScore findStudentScoreByIdLong(@PathVariable("id") Long id) {
        try {
            Thread.sleep(5000);    // 後端模擬獲取新數據的耗時,實際上可以做一個死循環判斷數據是否有更新
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return service.selectByPrimaryKey(id);
    }

}

參考文獻:

https://www.cnblogs.com/Joeris/articles/10999373.html

https://blog.csdn.net/qq_39767955/article/details/81099004

https://blog.csdn.net/baidu_38990811/article/details/79172163

https://blog.csdn.net/qq_33535433/article/details/79098526

https://segmentfault.com/q/1010000010996619

https://blog.csdn.net/weixin_34228617/article/details/87958339

https://www.v2ex.com/t/506933

https://www.jianshu.com/p/7d9c9e7a7656

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章