大文件传输

  1. 数据压缩:默认开启,通常是保底的。详见内容协商

    • request Accept-Encoding header

    • response Content-Encoding header

  2. 分块传输:response 化整为零

  3. 范围请求:request 化整为零。可以仅一个范围,也可以多个范围

以上四种方式不是互斥的,可以混合起来使用。

分块传输

一个 response 报文的 body 总长度,要么已知 Content-Length,要么未知 chunked

# 报文里的 body 不是一次性全发过来,而是分成了许多的 chunks 块逐个发送
Transfer-Encoding: chunked

分块传输时 body 的编码规则:length 和 chunked data,如下:

每个 chunk 包含两个部分:length 是 16 进制的数字,data 紧跟在 length 之后,最后也以 CRLF 结尾,但数据不包含 CRLF。

最后用一个 length 为 0 的 chunk 表示结束,即 0\r\n\r\n。其中,第一个 \r\n 表示 CRLF(回车换行),第二个 \r\n 表示正常 HTTP 报文中 header 和 body 的分隔空行。

需要说明的是,浏览器在收到分块传输的数据后,会自动按照规则去掉分块编码,重新组装好内容。若想看 server 发出的分块的原始报文形态,要用 Wireshark 抓包,或用 Telnet 手工发送请求。

范围请求

范围请求,range request,可以只获取部分数据,从而实现视频拖拽、断点续传、多段下载等。可以一次只请求一个范围,也可以一次请求“多个”范围。

范围请求,允许客户端在请求 header 里使用专用字段 Range 来表示只想获取文件的一部分。

Request
Server

Range: bytes=x-y

206 Partial Content Content-Range: bytes x-y/length

Range: bytes=x-y, x1-y1

Content-Type: multipart/byteranges; boundary=xx

Range

格式是 bytes=x-y,其中 x 和 y 是以字节为单位的数据偏移量,且都可以省略。

# request
Range: bytes=0-9    # 前 10 个字节
Range: bytes=10-19  # 第二个 10 字节
Range: bytes=0-10   # 前 11 个字节

Range: bytes=0-     # 从文档起点到文档终点,即整个文件
Range: bytes=10-    # 从第 10 个字节开始到文档末尾
Range: bytes=-1     # 文档的最后一个字节
Range: bytes=-10    # 从文档末尾倒数 10 个字节

在服务器收到 Range 字段后:

  1. 检查范围是否合法。若越界了,会返回状态码 416

  2. 如果范围正确,便根据 Range 计算偏移量,读取文件的片段

    • 206 Partial Content 状态码

    • Content-Range header 告诉片段的实际偏移量和资源总大小,格式是 bytes x-y/length

    • 发送数据,把片段用 TCP 发给客户端

# request
GET / HTTP/1.1
Host: www.xxx.com
Range: bytes=0-31
# response
HTTP/1.1 206 Partial Content
Content-Length: 32
Accept-Ranges: bytes
Content-Range: bytes 0-31/96

This is a plain text json doc.

多个范围

# response
Content-Type: multipart/byteranges; boundary=xx
  • MIME 类型 multipart/byteranges,表示报文的 body 是由多段字节序列组成的

  • 参数 boundary 给出段之间的分隔标记

多段数据的格式,如下:

  • 每个分段必须以 --boundary 开始

  • 之后用 Content-TypeContent-Range 标记这段数据的类型和所在范围

  • 最后用一个 --boundary-- 表示所有的分段结束

# request
GET / HTTP/1.1
Host: www.xxx.com
Range: bytes=0-9, 20-29
# response
HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=00000000001
Content-Length: 189
Connection: keep-alive
Accept-Ranges: bytes


--00000000001
Content-Type: text/plain
Content-Range: bytes 0-9/96

// this is
--00000000001
Content-Type: text/plain
Content-Range: bytes 20-29/96

ext json d
--00000000001--

这时响应报文的 body 里的多个部分会用 boundary 字符串 00000000001 分隔。

Last updated