用了这么久HTTP, 你是否了解Content-Length?
摘要: 理解HTTP协议...
由Content-Length导致的问题引发的一系列思考:
前段时间开发API网关, 使用postman调试时出现了超时的情况, 经排查确定是请求数据被处理后Content-Length
与实际不一致导致的问题, 故有此文.
Content-Length
, HTTP消息长度, 用十进制数字表示的八位字节的数目. 一般情况下, 很多工作都被框架完成, 我们很少去关注这部分内容, 但少数情况下发生了Content-Length
与实际消息长度不一致, 程序可能会发生比较奇怪的异常, 如:
- 无响应直到超时.
- 请求被截断, 而且下一个请求解析出现错乱.
Content-Length
是HTTP消息长度, 用十进制数字表示的八位字节的数目, 是Headers中常见的一个字段. Content-Length
应该是精确的, 否则就会导致异常 (特别地, HTTP1.0中这个字段可有可无).
Content-Length
首部指示出报文中实体主体的字节大小. 这个大小是包含了所有内容编码的, 比如, 对文本文件进行了gzip
压缩的话, Content-Length
首部指的就是压缩后的大小而不是原始大小.
Content-Length是如何工作的
Content-Length
使用十进制的数字表示了消息的长度, 服务端/客户端通过它来得知后续要读取消息的长度.
如果这个长度不正确, 会发生如下情况:
Content-Length > 实际长度
如果Content-Length比实际的长度大, 服务端/客户端读取到消息结尾后, 会等待下一个字节, 自然会无响应直到超时.
同样地, 在响应消息中Content-Length
超过实际长度也是一样的效果:
Content-Length < 实际长度
如果这个长度小于实际长度, 首次请求的消息会被截取, 比如参数为param=piaoruiqing
, Content-Length
为10, 那么这次请求的消息会被截取为: param=piao
, 如图所示:
但, 仅仅是如此吗, 当然不, 我们再来看看第二次请求会发生什么让人意外的事情, 如图:
连续的两次请求, 第一次消息被截断, 而第二次没有发生预期的截断, 而是服务端抛出了异常: Request method 'ruiqingPOST' not supported
.刺不刺激 (ノ)゚Д゚( )
那 ruiqingPOST
是个什么神仙方法??? 此时, 凭着多年开发(DEBUG)经验练就的敏感度, 我们大致可以猜出, 上一次请求被截取剩下的消息, 在这次请求出现了. 掏出wireshark来验证一下, 如图:
导致这种情况的原因就是开启了Connection:keep-alive
, 如果使用Connection:close
, 所产生的现象就是每一次的请求都被截断, 但不会产生解析混乱(如将上一次剩下的消息拼接到后续的请求消息中).
不确定Content-Length的值怎么办
Content-Length首部指示出报文中实体主体的字节大小. 但如在请求处理完成前无法获取消息长度, 我们就无法明确指定
Content-Length, 此时应该使用
Transfer-Encoding: chunked
什么是Transfer-Encoding: chunked
数据以一系列分块的形式进行发送. Content-Length
首部在这种情况下不被发送. 在每一个分块的开头需要添加当前分块的长度, 以十六进制的形式表示,后面紧跟着 \r\n
, 之后是分块本身, 后面也是\r\n
. 终止块是一个常规的分块, 不同之处在于其长度为0.
Transfer-Encoding: chunked是如何工作的
接下来我们用一个下载文件的例子, 来探讨Transfer-Encoding: chunked
是如何工作的. 服务端代码如下:
使用postman发起请求, wireshark抓包查看, 如图:
在wireshark中可以很清晰地看到chunked的数据, 其结构大致是: 返回的消息被分为多个数据块, 每个数据块有两部分, 长度
+ 数据
, 这两部分都以CRLF(即\r\n
)结尾. 而终止块是一个特殊的数据块, 其长度为0, 如图:
如此, 即完成了分块编码. 其主要应用于如下场景, 即要传输大量的数据, 但是在请求在没有被处理完之前响应的长度是无法获得的. 例如, 当需要用从数据库中查询获得的数据生成一个大的HTML表格、需要传输大量的图片等.
Content-Length
如果存在且生效, 必须是正确的, 否则会发生异常.(大于实际值会超时, 小于实际值会截断并可能导致后续的数据解析混乱)- 如果报文中包含
Transfer-Encoding: chunked
首部, 那么Content-Length
将被忽略.
参考
- https://developer.mozilla.org
- 《HTTP权威指南》
版权声明
本文发布于朴瑞卿的博客, 允许非商业用途转载, 但转载必须保留原作者朴瑞卿 及链接:https://blog.piaoruiqing.com. 如有授权方面的协商或合作, 请联系邮箱: piaoruiqing@gmail.com.
关于Fundebug
Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了20亿+错误事件,付费客户有阳光保险、核桃编程、荔枝FM、掌门1对1、微脉、青团社等众多品牌企业。欢迎大家免费试用!
用了这么久HTTP, 你是否了解Content-Length?的更多相关文章
- 那些年黑了你的微软BUG
本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 前言 炎炎夏日,朗朗乾坤,30℃ 的北京,你还在 Coding 吗? 整个 7 月都在忙项目,还加了 ...
- 深入研究HTTP协议以及部分应用
引言 工作了一段时间,都是在开发网页,自然和http打交道打得最多了,投身工作之后原来理解的东西又变得模糊,所以有必要深入探讨一下http协议的细节,也借此总结一下学习的成果. HTTP相关认识 对H ...
- No zuo no die:DDD 应对具体业务场景,Domain Model 重新设计
写在前面 上联:no zuo no die why you try 下联:no try no high give me five 横批: let it go上联:no zuo no die why y ...
- 微信小程序之知乎日报
上一次的<微信小程序之小豆瓣图书>制作了一个图书的查询功能,只是简单地应用到了网络请求,其他大多数小程序应有的知识.而本次的示例是知乎日报,功能点比较多,页面也比上次复杂了许多.在我编写这 ...
- Python之路【第十二篇】前端之js&dome&jQuery
JavaScript是一种属于网络的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果.通常JavaScript脚本是通过嵌入在HTML中来实现 ...
- python学习笔记十三 JS,Dom(进阶篇)
JS介绍 JavaScript 是属于网络的脚本语言!JavaScript 被数百万计的网页用来改进设计.验证表单.检测浏览器.创建cookies,以及更多的应用:JavaScript 是因特网上最流 ...
- 对抗静态分析——so文件的加密
[预备起~~~]最近在忙找工作的事情,笔试~面试~笔试~面试...很久没有写(pian)文(gao)章(fei).忙了一阵子之后,终于~~~到了选offer的阶段(你家公司不是牛吗,老子不接你家off ...
- 关于12306登陆页面dynamicJs的获取
今天帮与一个朋友探讨此事,刚开始一直是以为访问404,但是发现返回为200,没有问题,后来才知道朋友想了解的是为何浏览器可以获取到/otn/dynamicJs,但是自己手动获取就获取不到了 找了很久r ...
- 谈一谈CloudBlog的系统架构
---------------------------------------------------------------------------------------------[版权申明:本 ...
- java应用:向用户注册的邮箱发送邮件
实现功能 忘记密码,注册成功等向用户发送验证码信息或注册信息. 业务流程 忘记密码: 1.验证邮箱是否注册过: 2.向邮箱发送验证码: 3.验证验证码是否正确: 4.重新设置密码: 我这里着重介绍发送 ...
随机推荐
- linux for games; steamos; fedora game distribution
最近对linux 游戏发行版系统产生了兴趣,下面简要记录一些链接: https://itsfoss.com/linux-gaming-distributions/ (9 款游戏系统) https:// ...
- 阅读webpack代码笔记:antd-layout的webpack.config.prod.js
'use strict'; const autoprefixer = require('autoprefixer');//自动补全css前缀 const path = require('path'); ...
- React: React集成脚本库Fetch
一.简介 React功能虽然很强大,但是说到底它仍然只是一个简单的创建视图的脚本库,如果想要实现一些更为复杂的业务逻辑,我们还需要使用React搭配其他的脚本库协同工作,以提高应用程序的性能.其中,F ...
- java开发两三事(2)-java多数据源+java8stream与LocalDateTime时间差
1. 场景描述 最近在工作中碰到的几个问题,有点坑,记录下,遇到相同或类似问题的朋友可以参考下. 2. 解决方案 2.1 拼接sql后,多数据源执行 采用Spring+DruidDataSource数 ...
- Provide Several View Variants for End-Users 为最终用户提供多个视图变体
In this lesson, you will learn how to provide several customized variants of the same View, and allo ...
- GO基础之延时执行
一.延迟是什么?•即延迟( defer)语句,延迟语句被用于执行一个函数调用,在这个函数之前,延迟语句返回. 一.延迟函数 1.可以在函数中添加多个defer语句.•当函数执行到最后时,这些defer ...
- idea使用maven中的tomcat插件开启服务出现java.net.BindException: Address already in use: JVM_Bind :8080错误原因
[INFO] create webapp with contextPath: /maven_web 五月 11, 2019 6:05:26 下午 org.apache.coyote.AbstractP ...
- Class文件结构-练习题1
package org.fenixsoft.clazz; public class TestClass { private int m; public int inc() { return m + 1 ...
- vue中使用element组件时事件想要传递其他参数的问题
在使用element的上传组件时在一下几个钩子中传递其他参数 图中是文件上传时的几个钩子,参数为文件或文件列表或者其他参数,但是现在我想在原有参数上传递其他参数.比如我想在on-success的钩子中 ...
- Windows宏病毒利用
背景: 最近忙的飞起,各种事情,不想吐槽,因为某些事情,还吃了口屎,啧啧啧..... 常见的钓鱼,社工基本技术都是这种,什么鱼叉,水坑,社工,投毒之类的,APT 攻击惯用伎俩. 那么今天主要利用Win ...