NodeJS发送大体积POST JSON请求在低配置设备上被截断问题
问题根因定位
- Content-Length字段赋值错误
你代码里给Content-Length赋值用的是body.length,这个值是字符串的字符数,而HTTP协议要求的Content-Length是请求体的字节数。如果JSON中存在多字节UTF-8字符(比如中文、特殊符号),字符数会小于字节数,导致你填写的Content-Length比实际要发送的字节数小,服务器收到指定长度的内容后就会停止读取,自然会截断末尾内容。你手动加4个空格刚好补上了缺失的字节数差值,所以临时生效。
- Content-Length字段赋值错误
- 未等待请求完全发送就结束进程
你用stream.pipe(req)发送数据,但没有监听请求的finish事件,也没有阻塞进程等待发送完成。台式机性能好,IO调度优先级高,数据能快速全部写入内核TCP缓冲区;而旧笔记本性能弱,TCP发送缓冲区更小,数据还没完全写入缓冲区时进程就已经退出,未发送的尾部数据直接被丢弃。
- 未等待请求完全发送就结束进程
- 不必要的流转换引入额外风险
三百多KB的请求体完全可以直接写入请求对象,不需要额外转成Readable流再pipe,流的背压处理逻辑在性能较弱的设备上可能出现未覆盖的边界问题。
- 不必要的流转换引入额外风险
修复方案
第一步:修正Content-Length赋值
把headers里的Content-Length改为Buffer.byteLength(body, 'utf8'),确保值是实际的字节数。
第二步:简化发送逻辑,监听发送完成事件
直接用req.write+req.end发送数据,添加finish事件监听确认发送完成,避免进程提前退出:
const http = require('http'); const hostname = 'hostname'; const port = 3000; const path = '/my/path'; const method = 'POST'; const body = JSON.stringify(VERYLARGEJSONOBJECT); const bodyBytes = Buffer.byteLength(body, 'utf8'); console.log(`Sending ${bodyBytes} bytes:`); const options = { hostname, port, path, method, headers: { 'Content-Type': 'application/json', 'Content-Length': bodyBytes } }; const req = http.request(options, (res) => { console.log(`Response statusCode: ${res.statusCode}`); // 响应接收完成后再退出,可根据业务逻辑调整 res.resume(); res.on('end', () => { process.exit(0); }); }); req.on('error', (error) => { console.error(error); process.exit(1); }); // 直接写入请求体后结束请求 req.write(body); req.end(); // 监听finish事件确认所有数据已写入系统缓冲区 req.on('finish', () => { console.log('All data has been sent'); });
可选:大体积请求体背压处理
如果后续要发送更大的请求体,可以监听drain事件处理背压:
const writeRes = req.write(body); if (!writeRes) { req.once('drain', () => { req.end(); }); } else { req.end(); }
验证方法
在旧笔记本上运行修复后的代码,打印发送的字节数和服务器接收到的字节数,确认两者一致即可。
内容的提问来源于stack exchange,提问作者Slyke
相关产品推荐
相关产品推荐

