背景
由于HTTP请求容易(被)取消或(被)中断,HTTP客户端常常获取不到完整的数据(数据传输中断)。因此作为客户端,在获取到了一部分数据后,更希望在后续的请求中获取剩余的数据,而不是一下子获取所有数据。同样的,在一次请求中获取一部分数据,也很利于存储空间不足的设备。比如(大型)文档中的某一页,或者需要嵌入的图片的尺寸。
范围请求是可选的 HTTP 的特性,假如接收方没有实现这个特性(或者不支持特定的资源),请求也可以被当作普通的 GET 请求来处理,且不影响两端交互。
响应首部字段 Accept-Ranges
服务器通过Accept-Ranges
告诉客户端,服务器支持的范围请求方式。
如果服务器对于请求的资源支持字节范围的请求,那么就会发送:
Accept-Ranges: bytes
如果服务器不支持任何形式的范围请求,那么就会如下:
Accept-Ranges: none
先决条件 If-Range、 If-Match 和 If-Unmodified-Since
在多次请求的过程中,资源如果发生变化,客户端通过范围请求获取到的资源与服务端实际的资源会不一致,为了避免这种情况的发生,可以给请求设定先决条件,满足先决条件时服务端才响应范围请求。
设定先决条件的请求首部字段有:
- If-Range:比较Etag标记或者比较资源时间。资源未更新时响应范围请求;否则返回200并发送全部资源
- If-Match:比较实体标记(ETag)。匹配则响应范围请求;否则返回412状态(先决条件失败)
- If-Unmodified-Since:比较资源的更新时间。没有更新则响应范围请求,否则返回412状态(先决条件失败)
请求首部字段 Range
Range 字段用来发送字节范围,来告诉服务器应该响应资源的哪些部分。可以声明一段字节的范围,也可以一次性声明多段字节范围。
字节范围的声明包含首字节的位置以及末字节的位置,一个合格的字节范围,可以是以下格式中的一种:
Range: bytes=start-end
请求两个位置之间的字节。[start,end]
,包含start
及end
位置的字节0-0
请求的字节长度为1,0-1
请求的字节长度为2。
如果最后一个字节位置被指定但是小于首字节位置,那么这个字节范围是无效的Range: -length
,请求最后length
个字节。Range: start-
,请求指定位置之后的所有字节。[start,
,包含start
位置的字节
Range字段不应该被用在非GET请求中。
客户端发送多个请求获取多段范围时,这些范围应当按照升序的方式排列(朝着最终能获取到完整资源的方向)。除非有特殊的需求,需要不连续的提前获取某一段内容。
范围请求头 Range 在其他头部成功处理完(什么概念呢,就是说假如没有此 Range 头, 最终会返回200)之后处理,如果请求返回的结果是304那么此请求头就会被忽略。
部分响应
如果所有先决条件都满足,服务器也支持此资源的范围请求,请求中声明的范围也都是合法且可以被满足的,服务端就会返回响应头 206 Partial Content 以及所请求的部分数据,并同时包含响应首部 Content-Range
来标明次次响应返回的数据范围。
如果先决条件不满足,返回 412 状态码;如果先决条件满足,但请求中声明的范围是无效或无法被满足的,服务器会返回 416 Range Not Satisfiable
206 响应的响应报文:
HTTP/1.1 206 Partial Content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-Range: bytes 21010-47021/47022
Content-Length: 26012
Content-Type: image/gif
... 26012 bytes of partial image data ...
如果传输不止一部分数据,此响应报文类似:
HTTP/1.1 206 Partial Content
Date: Tue, 14 Nov 1995 06:25:24 GMT
Last-Modified: Tue, 14 July 04:58:08 GMT
Content-Length: 1741
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
--THIS_STRING_SEPARATES
Content-Type: video/example
Content-Range: bytes 500-999/8000
...the first range...
--THIS_STRING_SEPARATES
Content-Type: video/example
Content-Range: bytes 7000-7999/8000
...the second range
--THIS_STRING_SEPARATES--