1. 程式人生 > >ASP.NET Core靜態檔案中介軟體[3]: 區間請求以提供部分內容

ASP.NET Core靜態檔案中介軟體[3]: 區間請求以提供部分內容

大部分針對物理檔案的請求都希望獲取整個檔案的內容,區間請求則與之相反,它希望獲取某個檔案部分割槽間的內容。區間請求可以通過多次請求來獲取某個較大檔案的全部內容,並實現斷點續傳。如果同一個檔案同時存放到多臺伺服器,就可以利用區間請求同時下載不同部分的內容。與條件請求一樣,區間請求也作為標準定義在HTTP規範之中。

HTTP區間請求

如果希望通過一個GET請求獲取目標資源的某個區間的內容,就需要將這個區間存放到一個名為Range的報頭中。雖然HTTP規範允許指定多個區間,但是StaticFileMiddleware中介軟體只支援單一區間。分割槽所採用的計量單位,HTTP規範並未做強制的規定,但是StaticFileMiddleware中介軟體支援的單位為Byte,也就是說,它是以位元組為單位對檔案內容進行分割槽的。

Range報頭攜帶的分割槽資訊採用的格式為bytes={from}-{to}({from}和{to}分別表示區間開始與結束的位置),如bytes=1000-1999表示獲取目標資源從1001到2000共計1000位元組(第1個位元組的位置為0)。如果{to}大於整個資源的長度,這樣的區間依然被認為是有效的,它表示從{from}到資源的最後一個位元組。如果區間被定義成bytes={from}-這種形式,同樣表示區間從{from}到資源的最後一個位元組。採用bytes=-{n}格式定義的區間則表示資源的最後n

個位元組。無論採用何種形式,如果{from}大於整個資源的總長度,這樣的區間定義就被視為不合法。

如果請求的Range報頭攜帶一個不合法的區間,服務端就會返回一個狀態碼為“416 Range Not Satisfiable”的響應,否則返回一個狀態碼為“206 Partial Content”的響應,響應的主體將只包含指定區間的內容。返回的內容在整個資源的位置通過響應報頭Content-Range來表示,採用的格式為{from}-{to}/{length}。除此之外,還有一個與區間請求相關的響應報頭Accept-Ranges,它表示服務端能夠接受的區間型別。例如,前面針對條件請求的響應都具有一個Accept-Ranges: bytes報頭,表示服務支援針對資源的區間劃分。如果該報頭的值被設定為none,則意味著服務端不支援區間請求。

區間請求在某些時候也會驗證資源內容是否發生改變。在這種情況下,請求會利用一個名為If-Range的報頭攜帶一個時間戳或者整個資源(不是當前請求的區間)的標籤。服務端在接收到請求之後會根據這個報頭判斷請求的整個資源是否發生變化,如果判斷已經發生變化,它會返回一個狀態碼為“200 OK”的響應,響應主體將包含整個資源的內容。只有在判斷資源並未發生變化的前提下,服務端才會返回指定區間的內容。

針對靜態檔案的區間請求

下面從HTTP請求和響應報文的角度來探討StaticFileMiddleware中介軟體針對區間請求的支援。我們依然沿用前面演示條件請求的例項,該例項中作為目標檔案的foobar.txt包含26個字母和10個數字,加上UTF文字檔案初始的3個字元(EF、BB、BF),所以總長度為39。我們傳送如下兩個請求分別獲取前面26個字母(3-28)和後面10個數字(-10)。

GET http://localhost:50000/foobar.txt HTTP/1.1
Host: localhost:50000
Range: bytes=3-28

HTTP/1.1 206 Partial Content
Date: Wed, 18 Sep 2019 23:38:59 GMT
Content-Type: text/plain
Server: Kestrel
Content-Length: 26
Content-Range: bytes 3-28/39
Last-Modified: Wed, 18 Sep 2019 23:15:14 GMT
Accept-Ranges: bytes
ETag: "1d56e76ed13ed27"

abcdefghijklmnopqrstuvwxyz
GET http://localhost:50000/foobar.txt HTTP/1.1
Host: localhost:50000
Range: bytes=-10

HTTP/1.1 206 Partial Content
Date: Wed, 18 Sep 2019 23:39:51 GMT
Content-Type: text/plain
Server: Kestrel
Content-Length: 10
Content-Range: bytes 29-38/39
Last-Modified: Wed, 18 Sep 2019 23:15:14 GMT
Accept-Ranges: bytes
ETag: "1d56e76ed13ed27"

0123456789

由於請求中指定了正確的區間,所以我們會得到兩個狀態碼為“206 Partial Content”的響應,響應的主體僅包含目標區間的內容。除此之外,響應報頭Content-Range(“bytes 3-28/39”和“bytes 29-38/39”)指明瞭返回內容的區間範圍和整個檔案的總長度。目標檔案最後修改的時間戳和標籤同樣會存在於響應報頭Last-Modified與ETag之中。

接下來我們傳送如下所示的一個區間請求,並刻意指定一個不合法的區間(50-)。正如HTTP規範所描述的那樣,在這種情況下可以得到一個狀態碼為“416 Range Not Satisfiable”的響應。

GET http://localhost:5000/foobar.txt HTTP/1.1
Host: localhost:5000
Range: bytes=50-

HTTP/1.1 416 Range Not Satisfiable
Date: Wed, 18 Sep 2019 23:43:21 GMT
Server: Kestrel
Content-Length: 0
Content-Range: bytes */39
為了驗證區間請求針對檔案更新狀態的檢驗,我們使用了請求報頭If-Range。在如下所示的這兩個請求中,我們分別將一個基準時間戳和檔案標籤作為這個報頭的值,顯然服務端針對這兩個報頭的值都將做出“檔案已經更新”的判斷。根據HTTP規範的約定,這種請求會返回一個狀態碼為“200 OK”的響應,響應的主體將包含整個檔案的內容。如下所示的響應報文就證實了這一點。
GET http://localhost:5000/foobar.txt HTTP/1.1
Range: bytes=-10
If-Range: Wed, 18 Sep 2019 01:01:01 GMT
Host: localhost:5000

HTTP/1.1 200 OK
Date: Wed, 18 Sep 2019 23:45:32 GMT
Content-Type: text/plain
Server: Kestrel
Content-Length: 39
Last-Modified: Wed, 18 Sep 2019 23:15:14 GMT
Accept-Ranges: bytes
ETag: "1d56e76ed13ed27"

abcdefghijklmnopqrstuvwxyz0123456789
GET http://localhost:50000/foobar.txt HTTP/1.1
User-Agent: Fiddler
Host: localhost:50000
Range: bytes=-10
If-Range: "123abc456"

HTTP/1.1 200 OK
Date: Wed, 18 Sep 2019 23:46:36 GMT
Content-Type: text/plain
Server: Kestrel
Content-Length: 39
Last-Modified: Wed, 18 Sep 2019 23:15:14 GMT
Accept-Ranges: bytes
ETag: "1d56e76ed13ed27"

abcdefghijklmnopqrstuvwxyz0123456789

靜態檔案中介軟體[1]: 搭建檔案伺服器
靜態檔案中介軟體[2]: 條件請求以提升效能
靜態檔案中介軟體[3]: 區間請求以提供部分內容
靜態檔案中介軟體[4]: StaticFileMiddleware
靜態檔案中介軟體[5]: DirectoryBrowserMiddleware & DefaultFilesMi