首頁 >Java >java教程 >JAVA支持HTTP斷點續傳

JAVA支持HTTP斷點續傳

大家讲道理
大家讲道理原創
2016-11-11 10:41:141302瀏覽

檔案下載是WEB網站提供的最基本服務,然而你知道HTTP的斷點續傳是怎麼實現的嗎?

背景

    這兩天在實現一個基於HTML5在線音視頻播放,由於文件是存放於企業網盤中的,HTTP不可達,因此需要用程式來實現文件的讀取和HTTP協議的下載。

    用Java實作文件下載也不用多說了,讀取文件,透過二進位流的方式往response裡寫就行了。 H5播放器調用也能進行播放了;然而當我控制進度的前進和後退時,問題來了,居然一點效果都沒有!沒有快轉播放器還叫播放器嗎?

分析

    首先看到播放器無法取得音視頻檔案的時間長度,很自然想到Content-Length屬性,後台透過file.length()取得檔案長度並設定到Content-Length上(代碼如下),前台播放器裡可以顯示音視頻的長度了,並且可以快進了;然而當我快退的時候,還是無效,同時後台報錯。

response.addHeader("Content-Length", file.length());

    換了一個HTTP檔進行比較測試,發現直接HTTP存取的能夠正常快轉快退。仔細分析兩者​​的request和response頭,發現了差異,請求參數 多瞭如下圖所示屬性,該屬性表名需要從服務端獲取的資源範圍,預設從第一個位元組開始取,快進快退實際上就是透過指定這個Range屬性來確定你所期望的起始點。

JAVA支持HTTP斷點續傳

然而這個屬性是在請求頭上的,客戶端又是怎麼知道要添加這個屬性呢?繼續尋找發現了Accept-Ranges這個屬性,屬性值是bytes,其表示是否接受取得其某個實體的一部分(例如檔案的一部分)的請求。 bytes:表示接受,none:表示不接受。與此對應的response中另外一個屬性Content-Range,其表名該回應所包含的部分物件為整個物件的哪個部分。完整回應頭如下:

JAVA支持HTTP斷點續傳

解決

根據上面的分析,我們就知道在服務端該怎麼處理了,首先在響應頭上添加Accept-Ranges。

response.setHeader("Accept-Ranges", "bytes");

接著判斷request中是否存在Range屬性,即是否指定的起點,若存在,則透過stream的skip直接跳到目標起點,最後加入Content-Range屬性表名目前區塊的起始和結束,完整程式碼如下:

stream = new FileInputStream(file);
if(request.getHeader("Range") != null) //客户端请求的下载的文件块的开始字节   
  {
    //从请求中得到开始的字节   
    //请求的格式是:   
    //Range: bytes=[文件块的开始字节]-  
    String range = StringUtils.substringBetween(request.getHeader("Range"), "bytes=", "-");
    long start = Long.parseLong(range);   
    //下载的文件(或块)长度   
    //响应的格式是:   
    //Content-Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节]   
    response.setHeader("Content-Length", String.valueOf(fileSize - start));   
                
    if (start != 0)  
    {
      //要设置状态   
      //响应的格式是:   
      //HTTP/1.1 206 Partial Content  
               response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);//206   
      //不是从最开始下载,   
      //响应的格式是:   
      //Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]   
      response.setHeader("Content-Range","bytes " + start + "-" + String.valueOf(fileSize - 1) + "/" + String.valueOf(fileSize));  
                
      stream.skip(start);
      }
    }
    responseBinaryStream(response, this.getContentType(FilenameUtils.getExtension(fileName)), stream);
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn