Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

传输大文件的方法 #34

Open
18888628835 opened this issue May 27, 2021 · 0 comments
Open

传输大文件的方法 #34

18888628835 opened this issue May 27, 2021 · 0 comments

Comments

@18888628835
Copy link
Owner

传输大文件的方法

数据压缩

在上面我们已经讲过 HTTP 传输数据时,有一个字段是 Accept-Encoding,它代表客户端支持的数据压缩的格式,这样服务器就可以选择其中一种,放到 Content-Encoding 中,再把原来的数据压缩后发送给浏览器。

如果压缩率有50%,那么原来100k 的数据就可以压缩成50k 大小,极大地提升传输效率。

这种压缩方式非常适合文本如(text/html)的压缩,不过并不适合传输图片、音频视频等数据,因为它们本身已经高度压缩了。

分块运输

除了数据压缩之外,还可以把大文件整体变小,分解成很多个小块,这样就可以把小块分发给浏览器,浏览器收到后复原。

这种方式有个好处,每次只收发一小部分,网络不会被大文件长时间占用,可以节省带宽资源。

这种方法在 HTTP 中叫 chunked 分块传输,在响应报文里用头字段 Transfer-Encoding:chunked 来表示。意思是报文的 body 可以分成多次发送。

分块传输可以用于流式数据,例如数据库动态生成的表单页面,这种情况下 body 数据的长度是未知的,无法在头字段 Content-Length 里给出确切的长度,所以也只能用 chunked 方式分块发送。

“Transfer-Encoding: chunked”和“Content Length”这两个字段是互斥的,也就是说响应报文里这两个字段不能同时出现,一个响应报文的传输要么是长度已知,要么是长度未知(chunked)。

范围请求

分块传输就是把大文件分成很多个小块,那么假设我希望获取大文件中特定的片段数据,显然没办法用分块传输做到。

HTTP 协议中,还有一种范围请求可(range requests)的概念,允许客户端在请求头里面使用专用字段来表示只获取文件的一部分。

在做范围请求前,需要 Web 服务器在响应头上使用字段 Accept-Ranges:bytes,明确告知客户端支持范围请求。不支持则可以不传这个字段或者设置为 none

请求头 Range 是 http 范围请求的专用字段,格式是 bytes=x-y,其中 x和 y 是以字节为单位的数据范围。

需要注意 x、y 表示的是偏移量,范围从0计算,比如前10个字节表示为0-9.

其中 x 和 y 是可以省略的,0-表示文档起点到终点,-1表示文档最后一个字节,-10表示从文档末尾倒数10个字节。

服务器收到 Range 字段后,需要做四件事

  • 检查范围是否合法。不合法可以返回416编码。

  • 范围正确,服务器需要根据 Range 头计算偏移量,读取文件的片段,返回206 Partial Content,表示 body 只是数据的一部分

  • 服务器需要加上响应头 Content-Range,告诉片段的实际偏移量和资源的总大小,格式则是bytes x-y/length,和请求头的 Range 字段区别是没有=号且范围后多了总长度。

  • 最后发送数据了

范围请求的常见应用是视频的拖拽进度和多段下载、断点续传等。

多段数据

范围请求还支持一次获取多个片段数据,可以在 Range 中使用多个x-y

这种情况需要一种特殊的 MIME 类型:multipart/byteranges,表示报文的 body 是由多段字节序列组成的,并且还要给一个参数 boundary=xxx给出段之间的分割标记。

image.png

小结

压缩 HTML 等文件是传输大文件的基本方法

分块传输可以流式收发数据,节省内存和带宽。使用响应头 Transfer-Encoding:chunked

范围请求可以只获取部分数据。主要应用于断点续传和视频拖拽等。使用请求头字段 Range 和响应头字段 Content-Range。相关响应状态码416和206

也可以一次性请求多个范围,此时响应报文的Content-type 是multipart/byteranges,body 部分多个部分会用 boundary 字符串分隔。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant