Http协议206状态码

之前一直不知道这个是用来干什么用的,面试的时候被问到了,所以就查阅相关文章,这里记下自己的理解。

首先来看206状态码(Partial Content)代表什么意思,来自维基百科:

服务器已经成功处理了部分GET请求。类似于FlashGet或者迅雷这类的HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。

该请求必须包含Range头信息来指示客户端希望得到的内容范围,并且可能包含If-Range来作为请求条件。

响应必须包含如下的头部域:

1) Content-Range用以指示本次响应中返回的内容的范围;如果是Content-Type为multipart/byteranges的多段下载,则每一multipart段中都应包含Content-Range域用以指示本段的内容范围。假如响应中包含Content-Length,那么它的数值必须匹配它返回的内容范围的真实字节数。 2) Date

3) ETag和/或Content-Location,假如同样的请求本应该返回200响应。

4) Expires, Cache-Control,和/或Vary,假如其值可能与之前相同变量的其他响应对应的值不同的话。

假如本响应请求使用了If-Range强缓存验证,那么本次响应不应该包含其他实体头;假如本响应的请求使用了If-Range弱缓存验证,那么本次响应禁止包含其他实体头;这避免了缓存的实体内容和更新了的实体头信息之间的不一致。否则,本响应就应当包含所有本应该返回200响应中应当返回的所有实体头部域。

假如ETag或Last-Modified头部不能精确匹配的话,则客户端缓存应禁止将206响应返回的内容与之前任何缓存过的内容组合在一起。 任何不支持Range以及Content-Range头的缓存都禁止缓存206响应返回的内容。

可以看出,206代表的意思也就是响应了部分内容,那肯定就需要有上边解释说的一些消息头来控制怎么通过每次得打部分内容的方式来完成整个的接收。利用的场景也就是对于大文件下载比较多,也就实现了断点续传的功能。

判断是否支持

如果我们不知道一个资源是不是支持206,怎么进行判断呢?或者说不支持的时候,服务器会有什么响应呢?

可以通过curl命令来看:

curl -I http://s0.cyberciti.org/images/misc/static/2012/11/ifdata-welcome-0.png

得到的结果是:

HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 30354
Connection: keep-alive
Server: nginx
Date: Thu, 12 Nov 2015 06:49:27 GMT
X-Whom: Dyno-l1-com-cyber
Cache-Control: public, max-age=432000000
Expires: Sat, 21 Jul 2029 06:49:27 GMT
Accept-Ranges: bytes
ETag: "3717312687"
Last-Modified: Mon, 05 Nov 2012 23:06:34 GMT
X-Origin-Type: StaticViaCBZORG
X-Cache: Miss from cloudfront
Via: 1.1 2587f87ca37d9b8f8c0f687522eec7f6.cloudfront.net (CloudFront)
X-Amz-Cf-Id: S9x3pY4-7rW7JEL3VsjOAjnNDS6Z4eS37G-IlK2xQtx6Ps9oNb84yQ==

值得我们注意的是Accept-Ranges: bytes这个消息头,他表明了服务器支持Range请求,且支持的单位是bytes,也就意味着支持断点续传,可以并行多range进行下载。如果说响应的是Accept-Ranges: none则表示不支持Range请求。

Range & Content-Range

知道了是支持的,那么下一步就是客户端告知服务器现在要的是哪个范围的内容,HTTP中规定的是用Range来告诉服务器的,他的语法是:

Range: range-unit=first-byte-pos "-" [last-byte-pos]

在HTTP 1.1中range-unit只支持bytesfirst-byte-poslast-byte-pos是可以省略的,当然不能同时省略。

例子:

# The first 500 bytes (byte offsets 0-499, inclusive):
Range: bytes=0-499
# The second 500 bytes (byte offsets 500-999, inclusive):
Range: bytes=500-999
#The final 500 bytes (byte offsets 9500-9999, inclusive):
Range: bytes=-500
# Or 
Range: bytes=9500-
# The first and last bytes only (bytes 0 and 9999): 
Range: bytes=0-0,-1
# Several legal but not canonical specifications of the second 500
# bytes (byte offsets 500-999, inclusive):
Range: bytes=500-600,601-999
Range: bytes=500-700,601-999

在HTTP中是通过Content-Range消息头来告知响应的是Range以及实际长度:

Content-Range: range-unit first-byte-pos "-" last-byte-pos "/" (instance-length | *)

range-unit一样还是bytes,后边跟着的是响应回来的范围,紧跟着就是instance-length,也就是当前资源的长度,也可以是*,此时意味着此时响应的时候还不知道具体的实际长度值。

例子:

# The first 500 bytes
Content-Range: bytes 0-499/1234
# The second 500 bytes:
Content-Range: bytes 500-999/1234
# All except for the first 500 bytes:
Content-Range: bytes 500-1233/1234
#The last 500 bytes:
Content-Range: bytes 734-1233/1234

继续看一个示例,通过命令:

curl -I  -H "Range: bytes=0-100" http://s0.cyberciti.org/images/misc/static/2012/11/ifdata-welcome-0.png

去请求得到资源的0-100字节内容,看结果就是:

HTTP/1.1 206 Partial Content
Content-Type: image/png
Content-Length: 101
Connection: keep-alive
Server: nginx
Date: Thu, 12 Nov 2015 06:49:27 GMT
X-Whom: Dyno-l1-com-cyber
Cache-Control: public, max-age=432000000
Expires: Sat, 21 Jul 2029 06:49:27 GMT
Accept-Ranges: bytes
ETag: "3717312687"
Last-Modified: Mon, 05 Nov 2012 23:06:34 GMT
X-Origin-Type: StaticViaCBZORG
Age: 6108
Content-Range: bytes 0-100/30354
X-Cache: Hit from cloudfront
Via: 1.1 1be4933d0f259d5a861e0edb37d06676.cloudfront.net (CloudFront)
X-Amz-Cf-Id: gbB-1F9Q1RU2U1vSaYZvzbi6xIQmWZlSbCAQ1a8IloRRZuAJaEuk3w==

可以看到响应码是206,同时可以看到响应Content-Range: bytes 0-100/30354,可以看出资源的长度是30354,而这里只是响应回来了0-100范围的内容,也就是长度是101的内容,也就是通过Content-Length: 101也可以知道。

看到了内容,此时我们可以尝试把资源分成两块得到,分别存储了,然后通过cat将他们合并到一起,得到真正的文件:

curl  -H "Range: bytes=0-20000" http://s0.cyberciti.org/images/misc/static/2012/11/ifdata-welcome-0.png -o part1
curl  -H "Range: bytes=20001-" http://s0.cyberciti.org/images/misc/static/2012/11/ifdata-welcome-0.png -o part2

可以看到第二次就没有写入具体的结束位置的值了,直接得到从20001位置之后的所有内容。

然后通过cat命令合并成一个文件:

cat part1 part2 >> xx.png

然后就可以查看这个图片内容了。

结语

最后关于利用nginx来实现断点续传的话,可以参考这篇文章:http://chenzhenianqing.cn/articles/926.html

同时如果是自己的服务的话,针对于下载,保存的文件名可以通过Content-Disposition:attachment; filename="xxx.xx"来指定。

参考:

  1. https://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81

  2. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

  3. http://www.cnblogs.com/ziyunfei/archive/2012/11/18/2775499.html

  4. http://blog.chinaunix.net/uid-25267728-id-4095080.html

  5. http://my.oschina.net/ososchina/blog/371468

  6. http://itindex.net/detail/52614-http-%E6%96%AD%E7%82%B9

发布于: 2015年 11月 12日