转载自HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP,本来是将这篇文章收藏在我的有道云笔记的,但是今天复习的时候看着这个标题这尴尬,这里转载一下…...

什么是传输编码?

传输编码在 HTTP 的报文头中,使用 Transfer-Encoding 首部进行标记,它就是指明当前使用的传输编码。

Transfer-Encoding 会改变报文的格式和传输的方式,使用它不但不会减少内容传输的大小,甚至还有可能会使传输变大,看似是一个不环保的做法,但是其实是为了解决一些特殊问题。

简单来说,传输编码必须配合持久连接去使用,为了在一个持久连接中,将数据分块传输,并标记传输结束而设计的,后面会详细讲解。

在早年间的设计里,和内容编码使用 Accept-Encoding 来标记客户端接收的压缩编码类型一样,传输编码还需要配合 TE 这个请求报文头来使用,用于指定支持的传输编码。但是在最新的 HTTP/1.1 协议规范中,只定义了一种传输编码:分块编码(chunked),所以并不需要再依赖 TE 这个头部。

这些细节,后面都会讲到。既然传输编码和持久连接是息息相关的,那我们就先来了解一下什么是持久连接。

持久连接(Persistent Connection)

持久连接通俗来讲,就是长连接,英文叫 Persistent Connection,其实按字面意思理解就好了。

在早期的 HTTP 协议中,传输数据的顺序大致分为发起请求、建立连接、传输数据、关闭连接等步骤,而持久连接,就是去掉关闭连接这个步骤,让客户端和服务端可以继续通过此次连接传输内容。

这其实也是为了提高传输效率,我们知道 HTTP 协议是建立在 TCP 协议之上的,自然有 TCP 一样的三次握手、慢启动等特性,这样每一次连接其实都是一次宝贵的资源。为了尽可能的提高 HTTP 的性能,使用持久连接就显得很重要了。为此在 HTTP 协议中,就引入了相关的机制。

在早期的 HTTP/1.0 协议中并没有持久连接,持久连接的概念是在后期才引入的,当时是通过 Connection:Keep-Alive 这个头部来标记实现,用于通知客户端或服务端相对的另一端,在发送完数据之后,不要断开 TCP 连接,之后还需要再次使用。

而在 HTTP/1.1 协议中,发现持久连接的重要性了,它规定所有的连接必须都是持久的,除非显式的在报文头里,通过 Connection:close 这个首部,指定在传输结束之后会关闭此连接。

实际上在 HTTP/1.1 中Connect 这个头部已经没有 Keep-Alive 这个取值了,由于历史原因,很多客户端和服务端,依然保留了这个报文头。

长连接带来了另外一个问题,如何判定当前数据发送完成。

判断传输完成

在早期不支持持久连接的时候,其实是可以依靠连接断开来判定当前传输已经结束,大部分浏览器也是这么干的,但这并不是规范的操作。应该使用 Content-Length 这个头部,来指定当前传输的实体内容长度。

下面举个例子,在保持持久连接的情况下,依赖 Content-Length 来确定数据发送完毕。

Content-Length 在这里起到了一个响应实体已经发送结束的判断依据。这样的情况下,我们就要求 Content-Length 必须和内容实体的长度一致,如果不一致,就会出现各种问题。

如上图所示,如果 Content-Length 小于内容实体的长度,则会截断,反之则无法判定当前响应已经结束,会将请求持续挂起造成 Padding 状态。

理想情况下,我们在响应一个请求的时候,就需要知道它的内容实体的大小。但是在实际应用中,有些时候内容实体的长度并没有那么容易获得。例如内容实体来自网络文件、或者是动态生成的。这个时候如果依然想要提前获取到内容实体的长度,只能开一个足够大的 Buffer,等内容全部缓存好了再计算。

但这并不是一个好的方案,全部缓存到 Buffer 里,第一会消耗更多的内存,第二也会更耗时,让客户端等待过久。

此时就需要一个新的机制,不依赖 Content-Length 的值,来判定当前内容实体是否传输完成,此时就需要 Transfer-Encoding 这个头部来判定。

Transfer-Encoding:chunked

前面也提到,Transfer-Encoding 在最新的 HTTP/1.1 协议里,就只有 chunked 这个参数,标识当前为分块编码传输。

分块编码传输既然只有一个可选的参数,我们就只需要指定它为 Transfer-Encoding:chunked ,后续我们就可以将内容实体包装一个个块进行传输。

分块传输的规则:

1. 每个分块包含一个 16 进制的数据长度值和真实数据。

2. 数据长度值独占一行,和真实数据通过 CRLF(\r\n) 分割。

3. 数据长度值,不计算真实数据末尾的 CRLF,只计算当前传输块的数据长度。

4. 最后通过一个数据长度值为 0 的分块,来标记当前内容实体传输结束。

在这个例子中,首先在响应头部里标记了 Transfer-Encoding: chunked,后续先传递了第一个分块 “0123456780”,长度为 b(11 的十六进制),之后分别传输了 “Hello CxmyDev” 和 “123”,最后以一个长度为 0 的分块标记当前响应结束。

chunked 的拖挂

当我们使用 chunked 进行分块编码传输的时候,传输结束之后,还有机会在分块报文的末尾,再追加一段数据,此数据称为拖挂(Trailer)。

拖挂的数据,可以是服务端在末尾需要传递的数据,客户端其实是可以忽略并丢弃拖挂的内容的,这就需要双方协商好传输的内容了。

在拖挂中可以包含附带的首部字段,除了 Transfer-Encoding、Trailer 以及 Content-Length 首部之外,其他 HTTP 首部都可以作为拖挂发送。

一般我们会使用拖挂来传递一些在响应报文开始的时候,无法确定的某些值,例如:Content-MD5 首部就是一个常见的在拖挂中追加发送的首部。和长度一样,对于需要分块编码传输的内容实体,在开始响应的时候,我们也很难算出它的 MD5 值。

注意这里在头部增加了 Trailder,用以指定末尾还会传递一个 Content-MD5 的拖挂首部,如果有多个拖挂的数据,可以使用逗号进行分割。

内容编码和传输编码结合

内容编码和传输编码一般都是配合使用的。我们会先使用内容编码,将内容实体进行压缩,然后再通过传输编码分块发送出去。客户端接收到分块的数据,再将数据进行重新整合,还原成最初的数据。

传输编码小结

我们对传输编码应该有一定的了解了。这里简单总结一下:

1. 传输编码使用 Transfer-Encoding 首部进行标记,在最新的 HTTP/1.1 协议里,它只有 chunked 这一个取值,表示分块编码。

2. 传输编码主要是为了解决持久连接里将数据分块传输之后,判定内容实体传输结束。

3. 分块的格式:数据长度(16进制)+ 分块数据。

4. 如果还有额外的数据,可以在结束之后,使用 Trailer 进行拖挂传输额外的数据。

5. 传输编码通常会配合内容编码一起使用。

此外,传输编码应该是所有 HTTP/1.1 的标准实现,应该都有支持,如果收到无法理解的经过传输编码的报文,应该直接返回 501 Unimplemented 这个状态码来回复即可。

HTTP的传输编码(Transfer-Encoding:chunked)的更多相关文章

  1. 网络标准之:IANA定义的传输编码

    目录 简介 IANA的传输编码方式 7bit 8bit binary quoted-printable base64 总结 简介 不同的系统或者协议可以接受的数据类型是不同的,如果要在那些不支持现有数 ...

  2. C# 字符编码类Encoding

    在网络通信中,很多情况下都是将字符信息转成字节序列进行传输.将字符序列转为字节序列的过程称为编码.当这些字节传送到接收方,接收方需要逆向将字节序列转为字符序列.这个过程就是解码. 常见编码有ASCII ...

  3. HTTP 协议中的 Content-Encoding 和 Transfer-Encoding(内容编码和传输编码)

    转自:http://network.51cto.com/art/201509/491335.htm Transfer-Encoding,是一个 HTTP 头部字段,字面意思是「传输编码」.实际上,HT ...

  4. HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP

    题图:by @Olga Hi,大家好,我是承香墨影! HTTP 协议在网络知识中占据了重要的地位,HTTP 协议最基础的就是请求和响应的报文,而报文又是由报文头(Header)和实体组成.大多数 HT ...

  5. WCF技术剖析之十九:深度剖析消息编码(Encoding)实现(下篇)

    原文:WCF技术剖析之十九:深度剖析消息编码(Encoding)实现(下篇) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话 ...

  6. rest-assured的根路径(root path)和URL编码(URL Encoding)

    一.根路径(Root path) 为了避免在body方法中使用重复的路径来断言,我们可以指定一个根路径(root path),比如: 我们以前的写法是: when(). get("/some ...

  7. HTTP的传输编码(Transfer-Encoding:chunked) / net::ERR_INVALID_CHUNKED_ENCODING

    https://blog.csdn.net/m0_37668842/article/details/89138733 https://www.cnblogs.com/jamesvoid/p/11297 ...

  8. HTTP协议之chunk编码(分块传输编码

    Transfer-Encoding: chunked 表示输出的内容长度不能确定,普通的静态页面.图片之类的基本上都用不到这个. 但动态页面就有可能会用到,但我也注意到大部分asp,php,asp.n ...

  9. 字符集与字符编码 (charset & encoding)

    乱码是个大坑,相信每个人都遇过,而且是个绕不过去的坑.我理解每个程序员都应该写一篇编码相关的博文,梳理自己对这一块的理解,下面是我反复理解多次之后的学习小结. 1.从记事本的不同编码说起: 打开记事本 ...

随机推荐

  1. 2018-2-13-win10-uwp-模拟网页输入

    title author date CreateTime categories win10 uwp 模拟网页输入 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 1 ...

  2. 【转载】VS Code 中的代码自动补全和自动导入包

    原文连接:https://maiyang.me/post/2018-09-14-tips-vscode/ VSCode 必须安装以下插件: 首先你必须安装 Golang 插件,然后再给 Go 安装工具 ...

  3. vs2019 解决方案加载报错

    1. 如图 解决方案: 1.先关闭vs: 2.把C:/Users/<users name>/AppData/Local/Microsoft/VisualStudio/14.0/Compon ...

  4. There is already an open DataReader associated with this Connection which must be closed first EF

    废话不多说,直接 上图,及解决办法.不过问题还不是太清楚到底为什么会出现这个情况..........  

  5. 关于hibernate5的映射文件和配置文件改变(转)

    转自:https://blog.csdn.net/m0_37840000/article/details/78823716 配置文件: <!DOCTYPE hibernate-configura ...

  6. 模型正则化,dropout

    正则化 在模型中加入正则项,防止训练过拟合,使测试集效果提升 Dropout 每次在网络中正向传播时,在每一层随机将一些神经元置零(相当于激活函数置零),一般在全连接层使用,在卷积层一般随机将整个通道 ...

  7. 第二阶段:2.商业需求文档MRD:1.M版本管理

    版本管理的例子.V=Version.注意大中小版本的区分.V1.2.2 第一个数字1就是大版本 中间的2就是中版本 末尾的2就是小版本.大版本就是方向的变更,比如我的用户之前主要是面向男性,现在要面向 ...

  8. Zookeeper面试总结,年后涨薪轻而易举

    此文不是入门教程,是需要一定的zookeeper基础的 zookeeper应用 同意命名服务 在分布式系统中,各个系统都有可能做为服务提供者,可以向外提供服务,这个时候就需要对服务的名字进行统一规划, ...

  9. Logback 学习指南 一

    因为项目中用到 SpringBoot,看到官方文档中提及默认的日志实现是 logback,因此就通过阅读手册和结合实践学习了下相关的知识,记录下以备查阅. 1. logback 是什么? logbac ...

  10. Visual Studio 2015 编译生成支持HTTPS协议的libcurl静态库

    由于之前的工作需要使用libcurl 开源项目库 在各种研究后发现无法使用HTTPS协议 后来经过各种翻阅文档,发现需要OpenSSL支持,这个需要自己下载并自己编译生成 lib 或者 dll 至于O ...