遥感影像免切片9:范围请求(Range Request)

320 阅读5分钟

1. 概述

Range Request (以下称为_范围请求_)是 HTTP/1.1 协议中新增的请求/响应方式,允许服务器只发送 HTTP 消息的一部分数据到客户端,在传送大的媒体文件或者与断点下载功能搭配时非常有用。
范围请求是可选的 HTTP 特性,也就说,如果服务器没有实现这个特性(或者不支持特定的资源),客户端的请求也会被当做普通的 GET 请求来处理,并且不会影响两端交互。

2. 判断服务器是否支持范围请求

如果服务器在请求响应头中存在Accept-Ranges字段,并且它的值不为 none,那么表示该服务器支持范围请求。如果服务器在响应头中未发送Accept-Ranges字段,那么表示该服务器可能不支持范围请求。一些服务器应用会明确地将其值设置为 none,以此来表明不支持范围请求。
下面这个例子演示了通过 curl 工具查看 Minio 中文件请求的响应头信息,其中,-I表示向服务器发送 HEAD 请求,然后将服务器返回的响应头信息打印出来。响应结果中Accept-Ranges:bytes表示界定范围的是字节,Content-Length:13721580表示当前文件的字节大小。
image.png

3. 从服务器请求特定的范围数据

如果服务器支持 Range Request,则客户端可以使用在请求头中配置 Range 请求头来生成该类请求,表示指示服务器应该返回文件的哪一个或者哪几个部分。
Range 请求头的语法实例如下,其中:

  • unit 表示请求时所使用的单位,应该与服务器响应投中的Accept-Ranges的值保持一致;
  • 范围的起始值必须为整数,范围的起始值都为可选项,但必须存在一个;
  • 如果起始值不存在但存在结束值,则表示从文件某位开始取值,例如:Range: bytes=-500表示请求最后500个字节数据;
  • 如果起始值存在但结束值不存在,则表示从指定的开始位置一直到文件结束,例如:Range: bytes=500-表示从第500个字节开始请求一直到文件结束。
Range: <unit>=<start>-
Range: <unit>=<start>-<end>
Range: <unit>=<start>-<end>, <range-start>-<end>

3.1 单一范围请求示例

下面的这个例子演示了如何通过 curl 工具请求 COG.tif 前2个字节,其中,-H选项可以在请求中追加一个请求头,--ouput -选项可以在当前窗口中打印响应内容。在响应结果中,Content-Length响应值不再表示文件的字节大小而是表示当前请求的字节大小,Content-Range响应值首先表示了当前请求的内容在整个资源中所处的位置。对于响应内容,看过《01 | TIFF 文件结构》文章的朋友应该比较熟悉了,它是 IFH 中的开始的内容,表示小端字节序。
image.png

3.2 多重范围请求示例

由于 Minio 不支持多重范围请求,该示例以请求某网站的首页作为参考。示例演示了如何通过 curl 工具请求某网站首页前2个字节、第5-8字节。
image.png
在该实例响应结果与单一范围请求示例很不一样,具体来讲,Content-Type响应头的值为multipart/byteranges; boundary=00000000000000000006,其中,multipart/byteranges表示这响应有多个 byterange,每一部分 byterange 都有它自己的Content-TypeContent-Range响应头,并且使用 boundary 参数对 body 进行划分。

3.3 条件式范围请求

当客户端终端之后重新开始请求多个资源片段时,必须确保上一个片段别接收之后该资源没有进行过修改。
If-Range请求头可以用来生成条件式范围请求:如果满足设置的条件,条件请求就会生效,服务器会返回206状态码以及对应的消息主题;如果不满足设置的条件,那么就会范围200状态码,同时返回整个资源。该请求头使用示例为If-Range: Wed, 21 Oct 2015 07:28:00 GMT
If-Range请求头可以与Last-Modified或者ETag请求头一起使用,但是Last-ModifiedETag不能同时使用。

4. 范围请求的响应

HTTP 状态码中有3个与范围请求相关的响应:

  • 如果服务器响应成功,将返回206(Partial Content,部分内容)状态码,表示仅返回请求资源的部分内容。
  • 如果请求的范围超出资源的大小,则返回416状态码(Range Not Satisfiable)。
  • 当不支持范围请求的情况下,则返回200状态码,表示响应整个资源。

5. 范围请求与分块传输的对比

Transfer-Encoding请求头允许分块编码,这在数据量很大并且请求未能完全处理完成之前无法知晓响应的体积大小的情况下非常有用。服务器会直接把数据发送给客户端而无需进行缓冲或确定响应的精确大小(如果需要确定精确大小,会增加延迟)。范围请求与分块传输是兼容的,可以单独或者搭配使用。