千家信息网

Http协议Content-Length实例分析

发表于:2025-02-23 作者:千家信息网编辑
千家信息网最后更新 2025年02月23日,本篇内容主要讲解"Http协议Content-Length实例分析",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Http协议Content-Length实
千家信息网最后更新 2025年02月23日Http协议Content-Length实例分析

本篇内容主要讲解"Http协议Content-Length实例分析",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Http协议Content-Length实例分析"吧!

Http协议Content-Length详解

问题

我们的手机App在做更新时会从服务器上下载的一些资源,一般都是一些小文件,更新的代码差不多是下面这样的:

static void update() throws IOException {    URL url = new URL("http://172.16.59.129:8000/update/test.so");    HttpURLConnection conn = (HttpURLConnection) url.openConnection();    if(conn.getResponseCode() == 200) {        int totalLength = conn.getContentLength();    BufferedInputStream in = new BufferedInputStream(conn.getInputStream());    byte[] buffer = new byte[512];    int readLength = 0;    int length = 0;    while((length=in.read(buffer)) != -1) {        readLength += length;        //进度条        System.out.println(((float)readLength) /((float)(totalLength)));    }    }}

比如上面的代码更新一个so文件,先通过content-length获取文件的总大小,然后读Stream,每读一段,就计算出当前读的总大小,除以content-length,用来显示进度条。

结果weblogic从10升级到12后,content-length一直返回-1,这样就不能显示进度条了,但是文件流还能正常读。把weblogic重启了,一开始还能返回content-length,一会又是-1了。

原因分析

Http协议的请求报文和回复报文都有header和body,body就是你要获取的资源,例如一个html页面,一个jpeg图片,而header是用来做某些约定的。例如客户端与服务端商定一些传输格式,客户端先获取头部,得知一些格式信息,然后才开始读取body。

客户端: Accept-Encoding:gzip (给我压缩一下,我用的是流量,先下载下来我再慢慢解压吧)

服务端1:Content-Encoding:null(没有Content-Encoding头。 我不给压缩,CPU没空,你爱要不要)

服务端2:Content-Encoding:gzip (给你节省流量,压缩一下)

客户端:Connection: keep-alive (大哥,咱好不容易建了个TCP连接,下次接着用)

服务端1: Connection: keep-alive (都不容易,接着用)

服务端2: Connection: close (谁跟你接着用,我们这个TCP是一次性的,下次再找我还得重新连)

http协议没有三次握手,一般客户端向服务端请求资源时,以服务端为准。还有一些header并没有协商的过程,而是服务端直接告诉客户端按什么来。例如上述的Content-Length,是服务端告诉客户端body的大小有多大。但是!服务端并不一定能准确的提前告诉你body有多大。服务端要先写header,再写body,如果要在header里把body大小写进去,就得提前知道body大小。如果这个body是动态生成的,服务端先生成完,再开始写header,这样需要很多额外的开销,所以header里不一定有content-length。

那客户端怎么知道body的大小呢?服务器有三种方式告诉你。

1.服务器已经知道资源大小,通过content-length这个header告诉你。

Content-Length:1076(body的大小是1076B,你读取1076B就可以完成任务了)Transfer-Encoding: null

2.服务器没法提前知道资源的大小,或者不愿意花费资源提前计算资源大小,就会把http回复报文中加一个header叫Transfer-Encoding:chunked,就是分块传输的意思。每一块都使用固定的格式,前边是块的大小,后面是数据,然后最后一块大小是0。这样客户端解析的时候就需要注意去掉一些无用的字段。

Content-Length:nullTransfer-Encoding:chunked (接下来的body我要一块一块的传,每一块开始是这一块的大小,等我传到大小为0的块时,就没了)

3.服务器不知道资源的大小,同时也不支持chunked的传输模式,那么就既没有content-length头,也没有transfer-encoding头,这种情况下必须使用短连接,以连接结束来标示数据传输结束,传输结束就能知道大小了。这时候服务器返回的header里Connection一定是close。

Content-Length:nullTransfer-Encoding:nullConnection:close(我不知道大小,我也用不了chunked,啥时候我关了tcp连接,就说明传输结束了)

实验

我通过nginx在虚拟机里做实验,默认nginx是支持chunked模式的,可以关掉。

使用的代码如下,可能会调整参数。

static void update() throws IOException {    URL url = new URL("http://172.16.59.129:8000/update/test.so");    HttpURLConnection conn = (HttpURLConnection) url.openConnection();    //conn.setRequestProperty("Accept-Encoding", "gzip");    //conn.setRequestProperty("Connection", "keep-alive");    conn.connect();    if(conn.getResponseCode() == 200) {        System.out.println(conn.getHeaderFields().keySet());        System.out.println(conn.getHeaderField("transfer-encoding"));        System.out.println(conn.getHeaderField("Content-Length"));        System.out.println(conn.getHeaderField("Content-Encoding"));        System.out.println(conn.getHeaderField("Connection"));    }}

1.nginx在开启chunked_transfer_encoding的时候

(1) 在reqeust header里不使用gzip,也就是不加accept-encoding:gzip

test.so文件大小结果
100B能正常返回content-length,没有transfer-encoding头
69M能正常返回content-length,没有transfer-encoding头
3072M能正常返回content-length,没有transfer-encoding头

可以发现nginx不管资源多大,如果客户端不接受gzip的压缩格式,就不会使用chunked模式,而且跟是否使用短连接没关系。

(2)在request header里加入gzip,accepting-encoding:gzip

test.so文件大小结果
100B没有content-length,transfer-encoding=trunked
69M没有content-length,transfer-encoding=trunked
3072M没有content-length,transfer-encoding=trunked

可以看到nginx在开启chunked_transfer_encoding,并且客户端接受gzip的时候,会使用chunked模式,nginx开启gzip后不会计算资源的大小,直接用chunked模式。

2.nginx关闭chunked_transfer_encoding

(1) 在reqeust header里不使用gzip,也就是不加accept-encoding:gzip

test.so文件大小结果
100B能正常返回content-length,没有transfer-encoding头
69M能正常返回content-length,没有transfer-encoding头
3072M能正常返回content-length,没有transfer-encoding头

因为能很容易的知道文件大小,所以nginx还是能返回content-length。

(2)在request header里加入gzip,accepting-encoding:gzip

test.so文件大小结果
100B没有content-length和transfer-encoding头,不论客户端connection为keep-alive还是close,服务端返回的connection头都是close
69M没有content-length和transfer-encoding头,不论客户端connection为keep-alive还是close,服务端返回的connection头都是close
3072M没有content-length和transfer-encoding头,不论客户端connection为keep-alive还是close,服务端返回的connection头都是close

这就是上面说的第三种情况,不知道大小,也不支持trunked,那就必须使用短连接来标示结束。

问题解决方案

咨询了中间件组的同事,以前也遇到类似的问题,因为升级了Weblogic导致客户端解析XML出错,因为使用了chunked模式,中间有一些格式化的字符,而客户端解析的代码并没有考虑chunked模式的解析,导致解析出错。

因为我们客户端必须用content-length展示进度,因此不能用chunked模式,Weblogic可以把chunked模式关闭。用下面的方法:

#!java weblogic.WLST connect('username’,'password', 't3://localhost:7001')edit()startEdit()cd("Servers/AdminServer/WebServer/AdminServer")cmo.setChunkedTransferDisabled(true)save()activate()exit()

改了之后,确实不返回chunked了,但是也没有content-length,因为Weblogic就是不提前获取文件大小,而是强制加了connection:close,也就是前边说的第三种,通过连接结束标识数据结束。最后只能把这些资源放倒apache里了。

到此,相信大家对"Http协议Content-Length实例分析"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

大小 服务 客户 客户端 资源 文件 模式 服务器 传输 格式 结果 分析 代码 就是 时候 还是 进度 实例 实例分析 也就是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 北京通奥达网络技术 僧人网络安全教育简报 天下2为什么服务器断开连接 冀州网络技术团队 组装一台服务器该怎么配置 数据库故障代码 刘翔唱歌软件开发 安徽网络安全等级网 德惠正规网络技术服务参考价格 云服务器url 深圳c语言软件开发定做 结婚报名网络安全培训 嘉定区品牌人工智能应用软件开发 注册软件开发的公司经营范围 人工智能专业可以做软件开发么 怎样删除solaris数据库 超市数据库服务器连接不上 乌镇互联网大会2018新科技 组装塔式服务器多少钱 四川高清视频会议服务器设备 新时代如何维护网络安全论文 免费生鲜软件开发哪家专业 云服务器开直播 那些是文摘数据库 网络安全 培训内容 电子商务网络安全需求有哪些 计算社会学有哪些数据库 网络安全和信息化管理办公室 数据库数据表五种约束成表 网上互联网科技有限公司
0