前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HTTP 协议 Transfer-Encoding

HTTP 协议 Transfer-Encoding

作者头像
李振
发布2021-11-26 11:29:30
1.1K0
发布2021-11-26 11:29:30
举报
文章被收录于专栏:乱码李

简介

Transfer-Encoding (传输编码) 是常见的 HTTP 头 字段,表示将实体安全传递给用户所采用的编码形式。与另外一个更为常见的 Content-Encoding 不同,Content-Encoding 表示内容编码,通常用于对实体内容进行压缩编码,比如 gzip,deflate 等。而 Transfer-Encoding 不会减少实体内容传输大小,但是会改变实体传输的形式。Content-Encoding 和 Transfer-Encoding 二者是相辅相成的,对于一个 HTTP 报文,很可能同时进行了内容编码和传输编码。

在 HTTP 请求头中,Transfer-Encoding 被称为 TE,表示浏览器预期接受的传输编码方式,可使用 Response 头 Transfer-Encoding 字段中的值,比如 chunked;另外还可用 trailers 这个值来表明浏览器希望在最后一个大小为 0 的块之后还接收到一些额外的字段。

HTTP 长连接

HTTP/1.0 后期引入长连接的概念,通过 Connection: keep-alive 实现,服务端和客户端通过这个头部告诉对方发送完数据后不需要断开 TCP 连接,后面可以继续使用。HTTP/1.1 则将其变为默认规则,只要不发送 Connection: close,所有的连接均保持为长连接。

长连接存在的问题

持久链接需要服务器在开始发送消息体前发送 Content-Length 消息头字段,但是对于动态生成的内容来说,在内容创建完之前是不可知的。在 HTTP 协议中的 Transfer-Encoding 这篇文章中,作者举了两个例子来阐述长连接存在的问题。使用 node 创建 server。

代码语言:javascript
复制
require('net').createServer(function(sock) {
  sock.on('data', function(data) {
    sock.write('HTTP/1.1 200 OK\r\n')
    sock.write('\r\n')
    sock.write('hello world!')
    sock.destroy()
  })
}).listen(8080, '127.0.0.1')

使用 sock.destroy() ,则每次发送完请求后,就关闭 TCP 连接,假如去掉 sock.destroy(),服务变成长连接,但是请求的状态一直在 pending,因此浏览器无法确认数据是否传输完成,只能一直等待。通过设置 Content-Length 来解决这个问题。

代码语言:javascript
复制
require('net').createServer(function(sock) {
  sock.on('data', function(data) {
    sock.write('HTTP/1.1 200 OK\r\n')
    sock.write('Content-Length: 12\r\n')
    sock.write('\r\n')
    sock.write('hello world!')
  })
}).listen(8080, '127.0.0.1')

这样浏览器能正常接收响应数据,通过 Content-Length 判断实体已经结束,但是如果 Content-Length 计算错误会导致数据异常,并且对于动态生成的内容来说,在内容创建完之前其长度是不可知的。

Transfer-Encoding: chunked (分块传输编码)

Transfer-Encoding 的出现正是为了解决这个问题。如果一个 HTTP 消息(请求消息或应答消息)的 Transfer-Encoding 消息头的值为 chunked,那么,消息体由数量未定的块组成,并以最后一个大小为 0 的块为结束。分块传输编码只在 HTTP/1.1 中提供。

使用方式也很简单,在响应头部加上 Transfer-Encoding: chunked 后,就表示这个报文采用分块编码。每一个非空的块都以该块包含数据的字节数(字节数以十六进制表示)开始,跟随一个 CRLF (回车及换行),然后是数据本身,最后以一个大小为 0 的块 + CRLF 结束。

代码语言:javascript
复制
require('net').createServer(function(sock) {
  sock.on('data', function(data) {
    sock.write('HTTP/1.1 200 OK\r\n')
    sock.write('Transfer-Encoding: chunked\r\n')
    sock.write('\r\n')

    sock.write('24\r\n') // (36 字符 => 十六进制: 0x24)
    sock.write('This is the data in the first chunk \r\n')

    sock.write('1b\r\n') // (27 字符 => 十六进制: 0x1b)
    sock.write('and this is the second one \r\n')

    sock.write('3\r\n') // (3 字符 => 十六进制: 0x03)
    sock.write('con\r\n')

    sock.write('8\r\n') // (8 字符 => 十六进制: 0x08)
    sock.write('sequence\r\n')

    sock.write('0\r\n') // 块大小为 0 表示数据传输结束
    sock.write('\r\n')  // 消息最后以 CRLF 结尾
  })
}).listen(8080, '127.0.0.1')

用浏览器访问 http://localhost:8080/ 可以看到 “This is the data in the first chunk and this is the second one consequence”。

Transfer-Encoding 其它定义方法

  1. Transfer-Encoding: chunked:数据以一系列分块的形式进行发送。 Content-Length 首部在这种情况下不被发送。
  2. Transfer-Encoding: compress:采用 Lempel-Ziv-Welch (LZW) 压缩算法,这种内容编码方式已经被大部分浏览器弃用。
  3. Transfer-Encoding: deflate:采用 zlib 结构 (在 RFC 1950 中规定),和 deflate 压缩算法(在 RFC 1951 中规定)。
  4. Transfer-Encoding: gzip:表示采用 Lempel-Ziv coding (LZ77) 压缩算法,以及 32 位 CRC 校验的编码方式。这个编码方式最初由 UNIX 平台上的 gzip 程序采用。
  5. Transfer-Encoding: identity:用于指代自身(例如:未经过压缩和修改)。除非特别指明,这个标记始终可以被接受。

参考资料

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • HTTP 长连接
    • 长连接存在的问题
    • Transfer-Encoding: chunked (分块传输编码)
    • Transfer-Encoding 其它定义方法
    • 参考资料
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档