共计 3166 个字符,预计需要花费 8 分钟才能阅读完成。
HTTP Keep-Alive 模式客户端与服务器是如何判定传输完成,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
长连接是什么
我们知道 HTTP 协议采用“请求 - 应答”模式,当使用普通模式,即非 KeepAlive 模式时,每个请求 / 应答客户和服务器都要新建一个连接,完成 之后立即断开连接(HTTP 协议为无连接的协议);当使用 Keep-Alive 模式(又称持久连接、连接重用)时,Keep-Alive 功能使客户端到服 务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。
服务器如何知道已经完全接受客户端发送的数据
Content-Length 是一个实体消息首部,用来指明发送给接收方的消息主体的大小,即用十进制数字表示的八位元组的数目。
客户端如何知道已经完全接受服务端发送的数据
在 HTTP 1.0 短连接中客户端发送一个小请求,服务器响应以所期望的信息(例如一个 html 文件或一副 gif 图像)。服务器通常在发送回所请求的数据之后就关闭连接。这样客户端读数据时会返回 EOF(-1),就知道数据已经接收完全了。
消息首部字段 Conent-Length
消息首部字段 Transfer-Encoding
Transfer-Encoding
当客户端向服务器请求一个静态页面或者一张图片时,服务器可以很清楚的知道内容大小,然后通过 Content-length 消息首部字段告诉客户端需要接收多少数据。但是如果是动态页面等时,服务器是不可能预先知道内容大小,这时就可以使用 Transfer-Encoding:chunk 模式来传输数据了。即如果要一边产生数据,一边发给客户端,服务器就需要使用 Transfer-Encoding: chunked 这样的方式来代替 Content-Length。
chunk 编码将数据分成一块一块的发生。Chunked 编码将使用若干个 Chunk 串连而成,由一个标明长度为 0 的 chunk 标示结束。每个 Chunk 分为头部和正文两部分,头部内容指定正文的字符总数(十六进制的数字)和数量单位(一般不写),正文部分就是指定长度的实际内容,两部分之间用回车换行 (CRLF) 隔开。在最后一个长度为 0 的 Chunk 中的内容是称为 footer 的内容,是一些附加的 Header 信息(通常可以直接忽略)。
Transfer-Encoding 是一个用来标示 HTTP 报文传输格式的头部值。尽管这个取值理论上可以有很多,但是当前的 HTTP 规范里实际上只定义了一种传输取值——chunked。
如果一个 HTTP 消息(请求消息或应答消息)的 Transfer-Encoding 消息头的值为 chunked,那么,消息体由数量未定的块组成,并以最后一个大小为 0 的块为结束。
每一个非空的块都以该块包含数据的字节数(字节数以十六进制表示)开始,跟随一个 CRLF(回车及换行),然后是数据本身,最后块 CRLF 结束。在一些实现中,块大小和 CRLF 之间填充有白空格(0x20)。
最后一块是单行,由块大小(0),一些可选的填充白空格,以及 CRLF。最后一块不再包含任何数据,但是可以发送可选的尾部,包括消息头字段。消息最后以 CRLF 结尾。
一个示例响应如下:
HTTP/1.1 200 OKContent-Type: text/plainTransfer-Encoding: chunked25This is the data in the first chunk1A
and this is the second one0
注意:
chunked 和 multipart 两个名词在意义上有类似的地方,不过在 HTTP 协议当中这两个概念则不是一个类别的。multipart 是一种 Content-Type,标示 HTTP 报文内容的类型,而 chunked 是一种传输格式,标示报头将以何种方式进行传输。
chunked 传输不能事先知道内容的长度,只能靠最后的空 chunk 块来判断,因此对于下载请求来说,是没有办法实现进度的。在浏览器和下载工具中,偶尔我们也会看到有些文件是看不到下载进度的,即采用 chunked 方式进行下载。
chunked 的优势在于,服务器端可以边生成内容边发送,无需事先生成全部的内容。HTTP/2 不支持 instagram user search Transfer-Encoding: chunked,因为 HTTP/2 有自己的 streaming 传输方式(Source:MDN – Transfer-Encoding)。
transfer-coding 与 Content-Length
其实,上面 2 中方法都可以归纳为是如何判断 http 消息的大小、消息的数量。RFC 2616 对消息的长度总结如下:一个消息的 transfer-length(传输长度)是指消息中的 message-body(消息体)的长度。当应用了 transfer-coding(传输编码),每个消息中的 message-body(消息体)的长度(transfer-length)由以下几种情况决定(优先级由高到低):
任何不含有消息体的消息(如 1XXX、204、304 等响应消息和任何头 (HEAD,首部) 请求的响应消息),总是由一个空行(CLRF)结束。
如果出现了 Transfer-Encoding 头字段 并且值为非“identity”,那么 transfer-length 由“chunked”传输编码定义,除非消息由于关闭连接而终止。
如果出现了 Content-Length 头字段,它的值表示 entity-length(实体长度)和 transfer-length(传输长度)。如果这两个长度的大小不一样(i.e. 设置了 Transfer-Encoding 头字段),那么将不能发送 Content-Length 头字段。并且如果同时收到了 Transfer-Encoding 字段和 Content-Length 头字段,那么必须忽略 Content-Length 字段。
如果消息使用媒体类型“multipart/byteranges”,并且 transfer-length 没有另外指定,那么这种自定界(self-delimiting)媒体类型定义 transfer-length。除非发送者知道接收者能够解析该类型,否则不能使用该类型。
由服务器关闭连接确定消息长度。(注意:关闭连接不能用于确定请求消息的结束,因为服务器不能再发响应消息给客户端了。)
为了兼容 HTTP/1.0 应用程序,HTTP/1.1 的请求消息体中必须包含一个合法的 Content-Length 头字段,除非知道服务器兼容 HTTP/1.1。一个请求包含消息体,并且 Content-Length 字段没有给定,如果不能判断消息的长度,服务器应该用用 400 (bad request) 来响应;或者服务器坚持希望收到一个合法的 Content-Length 字段,用 411 (length required)来响应。
所有 HTTP/1.1 的接收者应用程序必须接受“chunked”transfer-coding (传输编码),因此当不能事先知道消息的长度,允许使用这种机制来传输消息。消息不应该够同时包含 Content-Length 头字段和 non-identity transfer-coding。如果一个消息同时包含 non-identity transfer-coding 和 Content-Length,必须忽略 Content-Length。
关于 HTTP Keep-Alive 模式客户端与服务器是如何判定传输完成问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注丸趣 TV 行业资讯频道了解更多相关知识。