午夜福利院在线观看免费,天堂最新版在线,色噜噜精品一区二区三区,无码一区二区三区中文字幕,丝袜美腿一区二区三区

首頁>文檔>技術(shù)文檔>使用http的Accept-Ranges實現(xiàn)json報文分段傳輸

此組別內(nèi)的文章

需要支持?

如果通過文檔沒辦法解決您的問題,請?zhí)峤还潍@取我們的支持!

使用http的Accept-Ranges實現(xiàn)json報文分段傳輸

背景

因為公司業(yè)務(wù)需求,對接一款終端設(shè)備,需要下載黑名單。可是設(shè)備的性能較差,每次下載的報文大小有限制。所以需要采用報文分段下載來實現(xiàn)。

當(dāng)然其實這種需求最好是用查詢分頁來達到分段下載是最好的,可是因為終端那邊實現(xiàn)問題還有以及其他各種原因,不得已采用這種分段下載方式。

找了很多帖子比較少有關(guān)于這種分段返回報文的內(nèi)容,可是有發(fā)現(xiàn)可以利用斷點下載的思想,去實現(xiàn)這個分段報文返回。有斷點下載經(jīng)驗的同學(xué),應(yīng)該很快能理解本文介紹的內(nèi)容,其實都是很皮毛的東西。
正題

分段下載我們主要用到兩個http頭信息:

http 響應(yīng)頭 Accept-Ranges
http 請求頭 Range

服務(wù)器使用 HTTP 響應(yīng)頭Accept-Ranges標(biāo)識自身支持范圍請求(partial requests)。字段的具體值用于定義范圍請求的單位。當(dāng)瀏覽器/客戶端發(fā)現(xiàn) Accept-Ranges 頭時,可以嘗試?yán)^續(xù)中斷了的下載,而不是重新開始。用法:Accept-Ranges: bytes

Range用來標(biāo)志本次請求,獲取數(shù)據(jù)的范圍。如:Range: bytes=100-200
步驟

客戶端請求頭都帶上Range,第一個請求Range:bytes=0-99,第二個Range:bytes=100-199,以此類推。
服務(wù)端除了響應(yīng)頭帶上Accept-Ranges: bytes,還需要根據(jù)請求中的Range來切割報文,返回Range范圍內(nèi)的數(shù)據(jù)。
http響應(yīng)碼設(shè)置為206
http響應(yīng)頭新增Content-Range,標(biāo)識本次響應(yīng)的內(nèi)容的范圍,和整個完整報文的長度
需要注意一點的是,Range單位是byte而不是字符數(shù),所以計算長度的時候要要將字符串換算成byte計算。

接下來展示controller層部分代碼:

    // 省略業(yè)務(wù)代碼
    //rsp為黑名單的響應(yīng)dto對象,全量的黑名單
    String returnJson = JsonUtil.Object2Json(rsp);
    httpResp.setContentType("application/json");
    //無緩存
    httpResp.setHeader("Cache-Control", "no-cache");
    //設(shè)置UTF-8編碼
    httpResp.setCharacterEncoding(Constant.CHARACTER_ENCODING);
    //可以斷點下載
    httpResp.setHeader("Accept-Ranges", "bytes");
    //設(shè)置http響應(yīng)碼為206
    httpResp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

    //獲取頭信息Range,并且去掉bytes=
    String range = httpReq.getHeader("Range").replaceAll("bytes=", "");
    String[] rangeSplit = range.split("-");

    //整段報文的總長度,要用utf-8的編碼字節(jié)長度計算
    int returnJsonLength = returnJson.getBytes("UTF-8").length;
    //offset 第一次請求默認(rèn)從0開始
    int offset = Integer.parseInt(rangeSplit[0]);
    // 初始化 length 和 endIndex
    // length:本次報文返回的長度;endIndex:本次報文結(jié)束的下標(biāo)位置,默認(rèn)是報文的總長度所以是returnJsonLength - 1
    int length = returnJsonLength - offset;
    int endIndex = returnJsonLength - 1;
    //設(shè)置 length 和 endIndex 值
    if (rangeSplit.length > 1) {
        //strSplit數(shù)組長度大于1,說明Range是一個范圍,而不是一個固定值
        endIndex = Integer.parseInt(rangeSplit[1]);
        //endIndex不允許大于等于報文長度
        if (endIndex >= returnJsonLength) {
            endIndex = returnJsonLength - 1;
        }
        //因為endIndex最大值比報文長度小于1的,而length是報文返回長度,所以要+1
        length = endIndex - offset + 1;
    }

    httpResp.setHeader("Content-Length", Long.toString(returnJsonLength));
    //Content-Range:bytes[json的開始字節(jié)]-[json的結(jié)束字節(jié)]/[報文的總大小]
    httpResp.setHeader("Content-Range", "bytes " + offset + "-" + endIndex + "/" + returnJsonLength);

    // 獲得寫出流
    try {
        OutputStream outputStream = httpResp.getOutputStream();
        //重點來了,輸出報文,只返回原完整報文的offset至offset + length的字節(jié)內(nèi)容
        outputStream.write(returnJson.getBytes("utf-8"), offset, length);
        outputStream.flush();
        outputStream.close();
    } catch (Exception e) {
        LogUtil.addProclog(procid, "返回報文錯誤:" + CommonUtil.getTrace(e));
    }

缺點:

每次請求只返回部分的報文,可是每次都是獲取全量的黑名單,數(shù)據(jù)庫查詢多次。可以用redis緩存黑名單,減少數(shù)據(jù)庫查詢。僅以記錄本次的解決方案,如果有更好的思路不妨一起交流一下,不才獻丑了。

0 條回復(fù) A文章作者 M管理員
    暫無討論,說說你的看法吧
QQ客服
  • QQ176363189 點擊這里給我發(fā)消息
旺旺客服
  • 速度網(wǎng)絡(luò)服務(wù)商 點這里給我發(fā)消息
電子郵箱
  • sudu@yunjiasu.cc
微信客服
  • suduwangluo