一、什么是chunked编码?

分块传输编码(Chunked transfer encoding)是只在HTTP协议1.1版本(HTTP/1.1)中提供的一种数据传送机制。以往HTTP的应答中数据是整个一起发送的,并在应答头里Content-Length字段标识了数据的长度,以便客户端知道应答消息的结束。

传统的Content-length解决方案:计算实体长度,并通过头部告诉对方。浏览器可以通过 Content-Length 的长度信息,判断出响应实体已结束

Content-length面临的问题:由于 Content-Length 字段必须真实反映实体长度,但是对于动态生成的内容来说,在内容创建完之前,长度是不可知的。

这时候要想准确获取长度,只能开一个足够大的 buffer,等内容全部生成好再计算。这样做一方面需要更大的内存开销,另一方面也会让客户端等更久。

我们需要一个新的机制:不依赖头部的长度信息,也能知道实体的边界——分块编码(Transfer-Encoding: chunked)。

对于动态生成的应答内容来说,内容在未生成完成前总长度是不可知的。因此需要先缓存生成的内容,再计算总长度填充到Content-Length,再发送整个数据内容。这样显得不太灵活,而使用分块编码则能得到改观。

分块传输编码允许服务器在最后发送消息头字段。例如在头中添加散列签名。对于压缩传输传输而言,可以一边压缩一边传输。

二、如何使用chunked编码

如果在http的消息头里Transfer-Encoding为chunked,那么就是使用此种编码方式。

接下来会发送数量未知的块,每一个块的开头都有一个十六进制的数,表明这个块的大小,然后接CRLF("\r\n")。然后是数据本身,数据结束后,还会有CRLF("\r\n")两个字符。有一些实现中,块大小的十六进制数和CRLF之间可以有空格。

最后一块的块大小为0,表明数据发送结束。最后一块不再包含任何数据,但是可以发送可选的尾部,包括消息头字段。

消息最后以CRLF结尾。

在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,报文中的实体需要改为用一系列分块来传输。

每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的 CRLF(\r\n),也不包括分块数据结尾的 CRLF(\r\n)。
最后一个分块长度值必须为 0,对应的分块数据没有内容,表示实体结束。
例:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

23\r\n
This is the data in the first chunk\r\n
1A\r\n
and this is the second one\r\n
3\r\n
con\r\n
8\r\n
sequence\r\n
0\r\n
\r\n

Content-Encoding 和 Transfer-Encoding 二者经常会结合来用,其实就是针对 Transfer-Encoding 的分块再进行 Content-Encoding压缩。

三、响应报文

1、构建响应报文

public static void main(String[] args) {

StringBuilder sb = new StringBuilder();
sb.append("HTTP/1.1 200 OK\r\n");
sb.append("Content-Type: text/plain\r\n");
sb.append("Transfer-Encoding: chunked\r\n");
sb.append("\r\n");

// chunkData
{
String line = "Hello,";
byte[] lineBs = line.getBytes();
int iOct = lineBs.length;
String sHex = SocketUtil.octToHex(iOct);
sb.append(sHex).append("\r\n");
sb.append(line).append("\r\n");
System.out.println("[" + line + "],iOct=" + iOct + ",sHex=" + sHex);
}

// chunkData
{
String line = "中国";
byte[] lineBs = line.getBytes();
int iOct = lineBs.length;
String sHex = SocketUtil.octToHex(iOct);
sb.append(sHex).append("\r\n");
sb.append(line).append("\r\n");
System.out.println("[" + line + "],iOct=" + iOct + ",sHex=" + sHex);
}

// chunk-end:0
{
sb.append("0").append("\r\n");
sb.append("\r\n");
}

2、解析响应报文

ByteBuffer in = ByteBuffer.allocate(1024);
in.put(sb.toString().getBytes());
in.flip();
int start = in.position();
int end = in.limit();
ByteBuffer content = ByteBuffer.allocate(1024);
while (true) { // 封包循环
for (int i = start; i < end - 1; i++) {
if (in.get(i) == 0x0D && in.get(i + 1) == 0x0A) {
byte[] nums = new byte[i - start];
in.get(nums);
// 丢弃\r\n
in.get(new byte[2]);
int num = Integer.parseInt(new String(nums), 16);
byte[] strs = new byte[num];
in.get(strs);
content.put(strs);
// 丢弃\r\n
in.get(new byte[2]);
start = i + 4 + num;
break;
}
}
if (in.get(start) == 0x30 && in.get(start + 1) == 0x0D && in.get(start + 2) == 0x0A
&& in.get(start + 3) == 0x0D && in.get(start + 4) == 0x0A) {
content.flip();
in.get(new byte[5]);
break;
}
}
System.out.println(new String(content.array(), 0, content.limit()));

四、例子

1、get

2、post

HTTP协议扫盲(八 )响应报文之 Transfer-Encoding=chunked方式的更多相关文章

  1. IP封包协议头/TCP协议头/TCP3次握手/TCP4次挥手/UDP协议头/ICMP协议头/HTTP协议(请求报文和响应报文)/IP地址/子网掩码(划分子网)/路由概念/MAC封包格式

    IP协议头IP包头格式: 1.版本号:4个bit,用来标识IP版本号.这个4位字段的值设置为二进制的0100表示IPv4,设置为0110表示IPv6.目前使用的IP协议版本号是4. 2.首部长度:4个 ...

  2. 重温Http协议--请求报文和响应报文

    http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应的内容再通过h ...

  3. Java Web ——http协议响应报文

    HTTP 响应报文 HTTP 响应报文由状态行.响应头部.空行 和 响应包体 4 个部分组成,如下图所示: 下面对响应报文格式进行简单的分析: 状态行:状态行由 HTTP 协议版本字段.状态码和状态码 ...

  4. 浅析HTTP协议的请求报文和响应报文

    1.HTTP协议与报文简介  HTTP(hypertext transport protocol),即超文本传输协议.这个协议详细规定了浏览器和万维网服务器之间互相通信的规则. 而客户端与服务端通信时 ...

  5. HTTP协议扫盲(二)HTTP协议的请求方法、请求头和响应头

    一.HTTP请求方法 Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST ...

  6. HTTP协议02-请求和响应的报文构成

    HTTP协议和TCP/IP协议族内的其他众多协议相同,用于客户端与服务器之间的通信,请求访问文本或图像等资源的一端+称为客户端,而提供资源响应的一端称为服务端. 应用HTTP协议时,请求必定是客户端发 ...

  7. HTTP协议-响应报文格式

    HTTP协议-响应码 浏览器向服务器发出请求,服务器处理可能是成功.可能是失败.可能没有权限访问等原因,服务器会通过响应码来告诉浏览器处理结果. " : OK " : Found ...

  8. Http协议--请求报文和响应报文

           http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应 ...

  9. PHP-02.文件上传、php保存/转移上传的文件、常见的网络传输协议、请求报文及属性、响应报文及属性

    关系数组 array("key"=>"value",...) ; get没有数据大小的限制 post上传大小没有限制 不指定上传方式,默认是get 文件上 ...

随机推荐

  1. 14.C++-二阶构造模式、友元(详解)

    首先回顾以前所学的构造函数 类的构造函数用于对象的初始化 构造函数与类同名并且没有返回值 构造函数在定义时被自动调用 由于构造函数没有返回值不能判断执行结果,所以不能保证初始化对象能否成功 比如: c ...

  2. 使用MBROSTool 工具制作本地硬盘多启动盘的方法总结

    前段时间写了一个自用五合一多启动盘分享--分别用来维护娱乐,wifi密码破解,win&mac登陆密码绕过/清除,反馈的同学还是挺多,觉得大家都有这方面的需求,于是再把自己的使用经验总结一下. ...

  3. 在VMWare上安装Arch Linux

    1.为什么选择Arch Linux Arch Linux 是通用 x86-64 GNU/Linux 发行版.Arch采用滚动升级模式,尽全力提供最新的稳定版软件.初始安装的Arch只是一个基本系统,随 ...

  4. Sql中根据旧表创建新表的SQL语句

    今天在网上查了下,根据旧表创建新表的SQL语句,网上给了两个答案 create table tab_new like tab_old (使用旧表创建新表) create table tab_new a ...

  5. ERROR : PHP中错误基础

    1.错误 在进行PHP代码编辑的时候,容易碰到error错误提示,PHP中错误有两种:语法错误.逻辑错误. 2.错误报告类型 Notice : 通知 比如直接使用未定义的变量,这种错误不影响PHP脚本 ...

  6. spring cloud 专题一 (spring cloud 入门搭建 之 Eureka注册中心搭建)

    一.前言 本文为spring cloud 微服务框架专题的第一篇,主要讲解如何快速搭建spring cloud微服务及Eureka 注册中心 以及常用开发方式等. 本文理论不多,主要是傻瓜式的环境搭建 ...

  7. 机器学习(1) - TensorflowSharp 简单使用与KNN识别MNIST流程

    机器学习是时下非常流行的话题,而Tensorflow是机器学习中最有名的工具包.TensorflowSharp是Tensorflow的C#语言表述.本文会对TensorflowSharp的使用进行一个 ...

  8. 由浅入深理解----java反射技术

    java反射机制详解 java反射机制是在运行状态下,对任意一个类可以获取该类的属性和方法,对任意一个对象可以调用其属性和方法.这种动态的获取信息和调用对象的方法的功能称为java的反射机制 clas ...

  9. Divisor counting [线性筛积性函数]

    Divisor counting 题目大意:定义f(n)表示整数n的约数个数.给出正整数n,求f(1)+f(2)+...+f(n)的值. 注释:1<=n<=1000,000 想法:我们再次 ...

  10. SDK提交到CocoaPods

    一:GitHub新建仓库,并clone到本地 1.注册GitHub账号并登录 2.右上方点击+,新建仓库(仓库名字(Repository name).仓库权限(Public).readme.licen ...