编写下载服务器。 第三部分:标头:内容长度和范围
這次,我們將探索更多的HTTP請求和響應(yīng)標(biāo)頭,以改善下載服務(wù)器的實現(xiàn): Content-length和Range 。 前者表示下載量很大,后者允許部分下載文件或在我們開始時失敗后繼續(xù)下載。
Content-length響應(yīng)標(biāo)頭對于跟蹤下載進(jìn)度的客戶端非常有用。 如果您在甚至開始流傳輸字節(jié)之前就提前發(fā)送了預(yù)期的資源大小,則Web瀏覽器之類的客戶端可以顯示非常準(zhǔn)確的進(jìn)度條,甚至可以通過測量平均下載速度來估計總下載時間。 如果沒有Content-length客戶端,則客戶端將一直保持下載盡可能長的時間,希望流結(jié)束一天。 但是,在某些情況下很難獲得準(zhǔn)確的內(nèi)容長度。 例如,也許您從其他下載服務(wù)器流式傳輸資源,或者您的資源被即時壓縮并直接發(fā)送到Servlet響應(yīng)。 在這兩種情況下,您能做的最好的事情就是實際上將數(shù)據(jù)本地緩存在磁盤上,弄清楚大小是多少,并在數(shù)據(jù)可用時開始流式傳輸。 這與始終流式傳輸,永遠(yuǎn)不要完全保留在內(nèi)存中的建議并不矛盾。 在這種情況下,我們將臨時文件存儲在磁盤上,但在完全準(zhǔn)備好并且知道其大小后仍將流式傳輸。
從Java的角度來看,提供內(nèi)容長度非常簡單:
private ResponseEntity<Resource> response(FilePointer filePointer, HttpStatus status, Resource body) {return ResponseEntity.status(status).eTag(filePointer.getEtag()).contentLength(filePointer.getSize()).lastModified(filePointer.getLastModified().toEpochMilli()).body(body); }請注意,還存在Resource.contentLength()方法,但是不同類型的資源對它的計算方式有所不同,有時會急于讀取整個資源。 我有自己的FilePointer抽象,知道我們要下載的文件大小。
Range標(biāo)頭是RFC 7233中很好描述的HTTP / 1.1的“新”功能。 這個想法是客戶端可以僅請求一部分資源(就字節(jié)范圍而言),主要有兩個原因:
- 先前的下載已中斷,我們不想重復(fù)相同的工作。 在這種情況下,客戶端知道收到了多少字節(jié)并要求剩余部分
- 我們正在流式傳輸數(shù)據(jù)(例如視頻),我們想跳過某些部分。 考慮一下像Youtube這樣的在線播放器,然后點擊進(jìn)度條中間的。 客戶可以簡單地估計它現(xiàn)在需要的文件部分,與電影持續(xù)時間成比例。
并非所有服務(wù)器都需要實現(xiàn)Range請求,因此需要進(jìn)行一些協(xié)商。 第一個客戶端發(fā)送一個請求,僅請求文件的一部分,在此示例中為前100個字節(jié):
> GET /big_buck_bunny_1080p_surround.avi HTTP/1.1 > Range: bytes=0-99 ...如果目標(biāo)服務(wù)器支持范圍請求,則響應(yīng)206 Partial Content :
< HTTP/1.1 206 Partial Content < Last-Modified: Tue, 06 May 2008 11:21:35 GMT < ETag: "8000089-375a6422-44c8e0d0f0dc0" < Accept-Ranges: bytes < Content-Length: 100 < Content-Range: bytes 0-99/928670754這里有很多有趣的標(biāo)題。 首先是206,而不是通常的200 OK。 如果為200 OK,則客戶端必須假定服務(wù)器不支持范圍請求。 示例服務(wù)器的運行情況非常好,它還會向我們發(fā)送Last-Modified和ETag標(biāo)頭,以改善緩存。 另外,服務(wù)器通過發(fā)送Accept-Ranges標(biāo)頭確認(rèn)其能夠處理Range請求。 當(dāng)前僅廣泛使用bytes ,但是RFC將來允許其他范圍單位(秒?幀?)最后兩個標(biāo)頭是最有趣的。 Content-Length不再聲明資源的總大小,而是我們請求的范圍的大小,在這種情況下為100字節(jié)。 完整資源的大小以Content-Range編碼: bytes 0-99/928670754 。 就我們收到的內(nèi)容而言,服務(wù)器非常精確:前100個字節(jié)( 0-99 ),而總資源大小為928670754 。 知道客戶端的總大小后,基本上可以請求多個文件中的文件部分。
Range請求的規(guī)范具有很大的靈活性,例如我們可以在一個請求中請求多個范圍,例如:
> GET /big_buck_bunny_1080p_surround.avi HTTP/1.1 > Range: bytes=0-9,1000-1009 ... < HTTP/1.1 206 Partial Content < Accept-Ranges: bytes < Content-Type: multipart/byteranges; boundary=5187ab27335732 <--5187ab27335732 Content-type: video/x-msvideo Content-range: bytes 0-9/928670754[data] --5187ab27335732 Content-type: video/x-msvideo Content-range: bytes 1000-1009/928670754[data] --5187ab27335732--但是,服務(wù)器可以自由地優(yōu)化多個范圍請求,例如重新布置它們,合并等。從頭開始實現(xiàn)部分請求超出了本文的范圍,我希望您不必自己做。 例如,從4.2.x開始的Spring對靜態(tài)資源的部分請求具有全面的內(nèi)置支持,請參閱: ResourceHttpRequestHandler第463行 。
編寫下載服務(wù)器
- 第一部分:始終流式傳輸,永遠(yuǎn)不要完全保留在內(nèi)存中
- 第二部分:標(biāo)頭:Last-Modified,ETag和If-None-Match
- 第三部分:標(biāo)頭:內(nèi)容長度和范圍
- 第四部分:有效地實現(xiàn)HEAD操作
- 第五部分:油門下載速度
- 第六部分:描述您發(fā)送的內(nèi)容(內(nèi)容類型等)
- 這些文章中開發(fā)的示例應(yīng)用程序可在GitHub上找到。
翻譯自: https://www.javacodegeeks.com/2015/07/writing-a-download-server-part-iii-headers-content-length-and-range.html
總結(jié)
以上是生活随笔為你收集整理的编写下载服务器。 第三部分:标头:内容长度和范围的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓音轨合成软件(安卓音轨)
- 下一篇: apache cxf_Apache CX