当前位置: 首页 > 后端技术 > Node.js

记得一个Content-Length导致的血案

时间:2023-04-03 16:12:32 Node.js

背景上线了一个新项目,发现了一个奇怪的BUG。请求接口有小概率返回400BadRequest。获取日志记录请求参数,在POSTMAN中测试请求接口,发现可以正常响应。在排查过程中,服务器可以先正常响应400BadRequest,排查接口故障。对比日志发现{"hello":"world"}接口可以正常响应业务数据。{"hello":"world","kw":"我是八哥"},接口返回400错误,接口的请求方式是postjson,于是开始复习代码。发现在发送请求的时候设置了Content-Length,在中文字符的情况下接口都返回400,原因定位。请求的伪代码如下letparam={"hello":"world","kw":"我是八哥"}let_options={headers:{'Content-Type':'application/json','Content-Length':JSON.stringify(param).length},url:url,method:'POST',json:true,time:true,timeout:5*1000,body:param}returnnewPromise((resolve,reject)=>{request(_options,(error,response,body)=>{///XXXX])})分析结果首先我们来说说什么是Content-Length,在http中的Content-Lengthheader该协议告诉浏览器消息中实体主体的大小。这个大小包括内容编码,比如对文件进行gzip压缩,Content-Length就是压缩后的大小(这个对我们写服务器很重要)。除非使用分块编码,否则具有实体主体的数据包需要Content-Length标头。使用Content-Length头的目的是为了能够检测到服务器崩溃导致的消息截断,并正确地分割共享一个持久连接的多条消息。其次,为什么包含汉字的请求参数会返回400,因为Content-Length是计算请求参数的字节数,而不是字符数。JSON.stringify(param).length返回字符数。汉字情况下,console.log('八太子'.length)//3,即3个字符console.log(Buffer.byteLength('八太子','utf8'));//9、utf-8编码下,一个汉字存储3个字节,接口层获取Content-Length小于实际字节长度,无法正确解析数据,从而返回400BadRequest。因此,需要将Content-Length的长度改为Buffer.byteLength(JSON.stringify(param),'utf8')