16 | 把大象装进冰箱:HTTP传输大文件的方法
16 | 把大象装进冰箱:HTTP传输大文件的方法
讲述:Chrono
时长11:16大小12.89M
数据压缩
分块传输
范围请求
多段数据
小结
课下作业
赞 37
提建议
精选留言(91)
- Aaaaaaaaaaayou2019-07-03老师,有个问题:http交给tcp进行传输的时候本来就会分块,那http分块的意义是什么呢?
作者回复: 在http层是看不到tcp的,它不知道下层协议是否会分块,下层是否分块对它来说没有意义,不关心。 在http里一个报文必须是完整交付,在处理大文件的时候就很不方便,所以就要分块,在http层面方便处理。 chunked主要是在http的层次来解决问题。
共 13 条评论82 - chengzise2019-07-031. 分块传输中数据里含有回车换行(\r\n)不影响分块处理,因为分块前有数据长度说明 2. 范围是应用于压缩后的文件
作者回复: 1正确。 2需要分情况,看原文件是什么形式。如果原来的文件是gzip的,那就正确。如果原文件是文本,而是在传输过程中被压缩,那么就应用于压缩前的数据。 总之,range是针对原文件的。
共 2 条评论68 - 赵健2019-07-04“Transfer-Encoding: chunked”和“Content-Length”这两个字段是互斥的,也就是说响应报文里这两个字段不能同时出现,一个响应报文的传输要么是长度已知,要么是长度未知(chunked),这一点你一定要记住。老师请问下,为啥分块意味着长度未知,后面不是提到块里面有个长度头嘛?而且单个块应该是一次http传输的内容,既然块里有长度头,那这次传输的内容长度也就能算出来,这次http的Content-Length 也就知道啊!是我理解错了吗展开
作者回复: 举个例子,从GitHub上下载源码包,GitHub要实时压缩实时发送,而不是一下子压缩好再发送,这样body的长度一开始就是未知的。 所以就要用分块编码,压缩一部分,就发一部分,这部分的长度是已知的,但总长度只有压缩完才能知道。 chunked编码用在“流式”收发数据的时候,通常数据是即时生成的,也就是动态数据。
共 4 条评论55 - 秋水共长天一色🌄2019-07-29老师,我有些问题需要问问您。 1.比如我在视频网上看电影,我们经常能看到进度条里面有一条灰色的缓存进度,我是否能理解成这个进度就是分块传输的一个进度显示吗? 2.刚刚我有看到评论说过一个问题就是分块传输的时候是由一个请求和一个响应完成的,如果我们在抓一个需要10分钟才能完成分块传输的请求时,我是不是就会看到这个请求在这10分钟内都是一个正在响应的状态吗? 3.为什么我们在对一些视频网站看视频抓包的时候却无法捕抓到这个请求呢? 4.如果我们在看完视频后在浏览器缓存里发现一些片段式的视频文件,能否就说明这个是用分块传输呢? 5.如果我们在看视频拖动进度条到10分30秒,到最后视频会从10分20秒开始播放,能否说明10分30秒的这个分块的头是在10分20秒呢? 6.请问多段数据能理解成一次性获取分块传输里多个连续的分块的数据的意思吗? 还有就是非常感谢老师把这些知识点讲的那么细,我近期多个面试里都有被问到相关的知识,多亏老师的讲解我才能顺利应付,谢谢老师!!!展开
作者回复: 1.网络视频不一定用的就是http协议,也可能是其他的专用协议,所以不能简单地判断就是分块传输。如果是http协议,对于大文件通常都是range请求,也不一定用chunk分块。 2.是的,这是由http的请求-应答工作模式决定的。不管是不是chunk,只要响应没有结束,这个来回就不会完成。 3.也可能用的是其他协议。 4.应该是range的分段,不是chunk,chunk只是在传输过程中分块,最后到客户端会是一个完整的文件。 5.视频文件的分段计算比较复杂,课程里面只是作为简单的示例,实际情况不一定就是这么简单。 6.分段的range和分块的chunk是两个完全无关的概念,不要弄混了。chunk是传输时分成小块逐个发送,range是取大文件中间的一部分。 7.不客气,后面的https、http/2也继续努力吧。
共 2 条评论49 - 小桶2019-07-20分块传输,客户端只需要发一次请求,还是发多次请求呢?使用分块传输时,客户端与服务器是怎样工作的呢
作者回复: http传输永远是一个请求一个响应的工作模式,只是响应是chunked分块,body数据不是一次性发过来的,而是分批分块发送,但仍然是在一个报文里。 客户端发送请求后等待响应,服务器组织数据,分块发送,最后一个分块是结束标志。客户端依次接收分块,收到结束标志后就把数据拼成完整的报文。
共 11 条评论40 - 一步2019-07-04对于问题2,range是针对原文的还是压缩后的,可以想象一下看视频的时候,我们拖拽进度条请求的range范围是针对原视频长度的,如果针对压缩后的,那么我们实际拖拽的范围和响应的数据范围就不一致了
作者回复: 说的很好。
20 - darren2021-04-07不分块:http把客户端需要的东西整个交给tcp,由tcp切块后发送给客户端,客户端接受后在tcp层组装完整发给浏览器使用。 分块:http把客户端需要的东西切分成1、2、3到n块,然后将1块发给tcp,tcp将块1再次切分后发给客户端,客户端接受后在tcp组装成块1发给http层。然后服务器与客户端用同样的方式发送块2、块3到块n。客户端的http在接收完所有块后组装成一个完整的响应。整个过程使用同一个tcp连接,块1到块n如上是挨个发送的。如果是http2,则基于多路复用技术块1到块n可以同时发送。所以分块抓包http只能抓到一个包,如果抓tcp的包,分不分块,都会抓到很多包。 分段:分段就是对某个资源的一部分进行请求(类似于把一个大文件切分成很多小文件,类似压缩中的分卷功能,然后客户端只对这些小文件中的一部分进行请求) 分段是对需要哪些资源进行一种说明,分块是一种传输机制,完全不同的两个东西,只是名字比较像。 请老师指教理解不正确的地方,另外想问一下老师分块的时候每个块都会复制一次响应头吗,还是只有块1带有请求头。展开
作者回复: 总结的非常好,很清晰。 chunk数据实际上是一个很大的请求,只有一个header,只是逐个地发出去,而不是一次性发。 可以在实验环境里抓包看看。
14 - -W.LI-2019-07-03老师好!在带宽固定的情况下,范围请求没发提高下载速度。如果服务器对客户端每个累链接限速的情况下,可通过多线程并发下载,提高下载速度是么?还有几个问题 分块传输:顺序传一次一小块 范围请求:支持跳跃式传输,还可以并发获取不同的range最后合并。 多段数据:一次请求多个范围,范围可以不连续是么?如果必须联系的话和请求一个大范围没差别了。 这几个拒的例子都是服务端这么返回的。 客户端上传的时候怎么使用呢?老师后面会讲么。 只读到了这么点,希望老师补充下每个的作用,和解决的问题,谢谢老师。展开
作者回复: 1,是的,通过多线程并发下载,提高下载速度。 2,范围可以不连续,例子里就是这样。 3,客户端上传的时候也可以用chunked、gzip,但不能用range。 注意这些字段的类型,只要是实体字段,那就在请求响应里都可以用。
14 - 一只鱼2020-04-10针对课下作业2: 情况一:如果服务器上只有 gzip 之后的文件,没有原文件,那范围请求针对的就是 gizp 之后的文件; 情况二:如果服务器上有原文件(未压缩),只是在传输过程中被 gizp , 那范围请求针对的就是未压缩的原文件。 这里拓展一下,假如在服务器和客户端之间有一个 cdn , 那么 cdn 缓存的是文件的某个范围吗?cdn 会根据请求头判断缓存里面有没有这个范围的结果,如果有就直接返回,并没有再根据bytes进行计算?展开
作者回复: 说的对。 第二个问题,如果按标准http协议的做法就是只缓存一个范围,但这样的效果不会很好,因为缓存的这部分被重复利用的机会很小。 更好的方法是cdn返回给客户端的同时,把整个文件都从源站取下来,之后就可以自己计算范围给客户端,不用再从源站取了。
11 - lesserror2019-12-04老师,请问一下:“分块传输也可以用于“流式数据””。该怎么理解这个“流式数据”这句话呢?
作者回复: 流式数据就是stream,虽然还是用一个个的chunk发过来的,但从更高层次上看,它像是从源头持续不断地、慢慢地“流”过来的,而不是一次性、一整块发过来的。 可以对比一下tcp和udp,tcp是流式数据,而udp是一个个的数据包。
6 - ly2019-08-18有几个小疑问: 分块传输: 对于一个500Mb的数据,客户端应该是发送N次http请求,每次http请求只传输其中一部分,每次都是采用了分块传输的body格式,那么每次都会重新建立TCP连接吗(三次握手)? 另外文章提到分块传输中的“流式数据”,这个流式数据怎么理解呢? 对于多段数据: 服务端在响应body里面的每一段都会指定Content-Type和Content-Range,总感觉其中的Content-Type字段是多余的,难道body里面的不同分段,Content-Type可能不一样?展开
作者回复: 1.请参考一下讲长连接的那一讲,现在的http请求应该都是使用的长连接,不会每次都重新建立连接,否则效率太低。 2.流式数据就是分块发送,像tcp那样一块一块地发过来,而不是像普通http那样一次完整地全发过来。 3.多段数据可以是mulitpart,每段数据是有可能不同的,比如发出一个请求,服务器返回了一个txt和json,所以要这么做。当然这种情况比较少见,但协议就必须要考虑到这种情况。
共 2 条评论6 - wheat72019-07-12chunk的核心问题并不是所谓把大象装进冰箱,是为了解决应用层在没有content-length的时候知道数据在哪里结束,chunk和普通传输方式都是在一个http报文里传输的,只是在body里相当于又加了一层协议或者是编码,数据无论如何是在一头大象里,在一个http报文中传输,大的数据传输使用chunk和不使用传输方式并没有什么区别。
作者回复: 说的很有道理。 不过两者还是有区别的,chunked主要用于流式数据,一开始不能知道准确的大小。
共 6 条评论6 - Gopher2019-07-03这个专栏质量很棒,老师很负责,知识讲解很通透,很容易就get、解惑了。 哈哈哈,特此留言就是想说,老师,你认真做事的样子真帅(*•̀ᴗ•́*)و ̑̑
作者回复: 承蒙夸奖,不胜感激。
5 - 四月长安2019-08-16http数据包封装好交给下层tcp协议的时候,应该是作为tcp数据部分所要传输的内容吧,ip协议数据报最大传输65535字节的数据,这65535的数据减去tcp的首部,应该就是tcp所能容纳的负载极限了吧,所以如果是这样的话http数据的分块应该粒度更小才是吧,或许一个tcp负载里边就有好多http分块?请老师指正,感谢🙏
作者回复: http层面的分块与tcp的分块是互不相关的,http的分块可以很大也可以很小,这些数据到了tcp由tcp去自行组织,是合并在一个块里还是跨越多个块都没有关系,我们不需要为此操心。 其实tcp层再往下的mac层,一个包最多1500字节,但tcp也不需要考虑这个,只要下层能够保证上层正确传输就好。
4 - 钱2020-03-29压缩和分而治之的思路是解决各种大问题的通用思路,思路容易理解,大东西放入小容器,要么把大东西变小也就是压缩,实在变小不了就弄多个容器把大东西分块放入多个容器之中,如果仅是传输之用那就一次传一点,有点类似愚公移山的动作。 比较关心大东西怎么拆?传输到对应的地方每一小块又怎么组合起来?比如:内存只有1G要传输10G的大文件,具体怎么拆分呢?是按照大小吗?比如:拆成20个0.5G的文件,如果这样传输到的内容也是需要保持一定的顺序的吧?否则组装也是一个问题,我能想到的最简单的方式就是表上号放置的时候按照序号一个个码放,不过我觉得应该不会这么简单,希望老师能分享一下,这块的具体实现逻辑。 目前在做的一个项目就涉及大文件上传、下载、解析的事情,量变引起质变感觉文件的体积大到一定程度,就不是一个简单的文件上传、下载、解析的事情了,需要各种考虑怎么提高性能减短处理时间的问题,还要考虑中间网络断了或者解析数据时遇到不OK的数据怎么处理的问题。展开
作者回复: 如果传输超大文件,用http就不太合适了,虽然也可以,但就会麻烦一些。可以考虑用其他方式,比如mq。
3 - 响雨2019-07-05响应报文返回的数据太大,所以采用了chunk分块传输的话,那响应报文在传输完成前是什么样子,响应行和头过来了,响应体还在流式传递,那响应体内的数据该怎么展示?
作者回复: 就是按照格式分成一些片段,逐块发送,浏览器收到后去掉分隔符,再拼成原来的样子。
3 - djfhchdh2019-07-031、因为分块数据是明文传输,如果数据里有\r\n,是会影响分块处理的 2、个人感觉应该是应用于原文件
作者回复: 1不对,因为chunked格式里已经有长度了。 2正确。 看来有不少同学对第二个问题比较迷惑,我再说具体一点。 比如说,有一个1M的纯文本,range请求其中的500K,然后服务器编码为gzip(Content-Encoding: gzip),压缩成200k,浏览器收到后解压缩,就得到了这部分的500k数据。
3 - 不二2020-12-16老师,问一个问题,这篇文章主要讲的是服务器端如何分块传输给客户端数据,或者客户端如何获取部分服务器端的数据, 那web客户端可以分批上传一个大文件的功能吗?类似于云盘中的上传功能
作者回复: 上传就要用chunked功能,流式发送数据,服务器流式接收数据。 range功能只能是下载用,不能上传。
共 3 条评论2 - Javatar2020-08-30老师你好,看完本节内容后,找了一个网络上的pdf,用telnet发了下请求,结果在响应报文中并没有看到chunked头,pdf也是大文件,但是并没有分块传输,该怎么理解?还是说大文件也可以不用分段传输? Trying 202.38.64.11... Connected to staff.ustc.edu.cn. Escape character is '^]'. GET /~bhua/Kurose_Labs_v7.0/Wireshark_HTTP_v7.0.pdf HTTP/1.1 Host: staff.ustc.edu.cn HTTP/1.1 200 OK Date: Sun, 30 Aug 2020 05:54:44 GMT Server: Apache/2.0.52 (Red Hat) Last-Modified: Thu, 19 Sep 2019 09:00:14 GMT ETag: "40d8086-2392cc-2e81a380" Accept-Ranges: bytes Content-Length: 2331340 Connection: close Content-Type: application/pdf %PDF-1.3 %????????? 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream ....省略body展开
作者回复: 是的,chunked只是传送大文件的一种方式,不是一定要用,而且大文件的定义也因网站而不同。 看一下文件头,里面有content-length头,那么这个很明显就是给出了确定长度,就不用chunked了。 chunked的应用场合主要是流式传送,内容的长度不确定,给不出content-length。
共 2 条评论2 - snake2020-06-221、使用chunk分段后还能压缩吗?或者说chunk分段分的是压缩后还是压缩前的文件呢?2、使用了chunk,为什么内存、带宽会节省呢?总的数据大小不变吧?内存的话,分段后,前面的数据到达浏览器客户端后,是存在内存还是磁盘呢?如何节省内存呢?
作者回复: 1.可以的,先压缩再分块。 2.分块的好处是每次只处理一小部分数据,比如一次只从磁盘读取10k,而不用把1G的文件都读进内存,发的时候也可以慢慢发,所以就节省了内存、带宽。 3.对方收到数据肯定是先在内存里,之后可以用各种策略,比如达到一定的大小(比如1M)就落盘存。
2