Node.js中HTTP请求end事件未触发问题求助
Node.js POST请求end事件未触发导致请求体为空的问题
我用Node.js编写简易服务器与网页,尝试处理POST请求并获取请求体。参考的示例代码运行正常,能正确输出请求体内容;但将相同代码复制到自己的服务器代码中后,请求体数组body始终为空,经排查发现HTTP Request的end事件未触发。他人在另一台机器运行我的代码时,end事件可正常触发,现寻求该问题的原因及解决办法。
参考示例代码
const http = require('http'); http.createServer((request, response) => { let body = []; request.on('data', (chunk) => { body.push(chunk); }).on('end', () => { body = Buffer.concat(body).toString(); console.log("Received "+request.method+" "+request.url); //note method is a string //the next line prints the http headers formatted for humans //it is still verbose so you may want it commented out //console.log("HTTP Headers "+JSON.stringify(request.headers,null,2)); console.log(body); response.end(body); }); }).listen(8080);
我的服务器代码(POST处理部分为关键代码)
const fs = require('fs'); const http = require('http'); const data = fs.readFileSync(process.argv[3]); let books = JSON.parse(data); http.createServer((req, res) => { console.log(req.url); if(req.url === '/client.html') { let page = fs.readFileSync('client.html'); res.writeHead(200, {'Content-Type': 'text/html'}); res.end(page); console.log(req.header); } else if (req.url === '/test.html') { let page = fs.readFileSync('test.html'); res.writeHead(200, {'Content-Type': 'text/html'}); res.end(page); console.log(req.header); } else if (req.url.substring(0,6) === "/book/") { if(req.method === "GET") { let book = 0; for(i=0;i<books.length;i++) { if(books[i].isbn === req.url.substring(6)) { book = books[i]; } } if(book === 0) { res.writeHead(404, {'Content-Type': 'text/plain'}); res.end(); } else { res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify(book)); console.log(res.header+"0"); } } else if(req.method === "POST") { let body = []; req.on('data', (chunk) => { body.push(chunk); }).on('end', () => { console.log("WE MADE IT"); body = Buffer.concat(body).toString(); console.log("Received "+req.method+" "+req.url); //note method is a string //the next line prints the http headers formatted for humans //it is still verbose so you may want it commented out console.log("HTTP Headers "+JSON.stringify(request.headers,null,2)); console.log(body); response.end(body); }); console.log(body); let book = JSON.parse(body); let found = false for(i=0;i<books.length;i++) { if(books[i].isbn === req.url.substring(6)) { found = true; } } if(!found) { books.push(book); res.writeHead(201, {'Content-Type': 'text/plain'}) res.end(); } else { res.writeHead(400, {'Content-Type': 'text/plain'}) res.end(); } } } else { let page = "404 File Not Found"; res.writeHead(404, {'Content-Type': 'text/html'}); res.end(page); } }).listen(process.argv[2]);
问题原因
你的POST处理逻辑存在异步事件未完成就提前结束响应的核心问题:
- Node.js的
data和end事件是异步触发的,你在绑定事件后立刻执行了JSON.parse(body)、数组遍历以及res.end()操作。此时请求体还没开始接收,body是空数组,JSON.parse会报错,而且你直接关闭了响应连接,导致后续的data和end事件完全没有触发的机会。 - 另外,
end回调里误用了request和response变量(你的回调参数是req和res),会导致运行时错误;同时没有绑定error事件,若请求过程中出现异常,也会导致end事件无法触发。
解决办法
把所有依赖请求体的业务逻辑全部移到end事件回调内部,确保请求体完全接收后再处理数据和响应:
修改后的POST处理代码
else if(req.method === "POST") { let body = []; req.on('data', (chunk) => { body.push(chunk); }).on('end', () => { console.log("WE MADE IT"); try { // 拼接并转换请求体 body = Buffer.concat(body).toString(); console.log(`Received ${req.method} ${req.url}`); console.log("HTTP Headers " + JSON.stringify(req.headers,null,2)); console.log(body); // 解析JSON请求体 let book = JSON.parse(body); // 检查ISBN是否存在 let found = false; // 声明局部变量i,避免污染全局作用域 for(let i=0;i<books.length;i++) { if(books[i].isbn === req.url.substring(6)) { found = true; break; // 找到后立即跳出循环,提升性能 } } // 根据结果返回响应 if(!found) { books.push(book); // 可选:将修改后的书籍列表写回文件,避免重启服务器丢失数据 fs.writeFileSync(process.argv[3], JSON.stringify(books, null, 2)); res.writeHead(201, {'Content-Type': 'text/plain'}); res.end('书籍添加成功'); } else { res.writeHead(400, {'Content-Type': 'text/plain'}); res.end('该ISBN对应的书籍已存在'); } } catch(err) { // 处理JSON解析错误或其他异常 console.error('处理请求时出错:', err); res.writeHead(400, {'Content-Type': 'text/plain'}); res.end('请求格式错误,请检查JSON格式'); } }).on('error', (err) => { // 处理请求接收过程中的异常,避免服务器崩溃 console.error('请求接收错误:', err); res.writeHead(500, {'Content-Type': 'text/plain'}); res.end('服务器内部错误'); }); }
额外优化建议
- 给循环变量
i添加let声明,避免全局变量污染; - 添加
try/catch块处理JSON解析失败的情况,增强鲁棒性; - 绑定
error事件,处理请求过程中的异常; - 将修改后的书籍数据写回文件,保证数据持久化;
- 响应时返回明确的文本提示,方便客户端判断请求结果。
内容的提问来源于stack exchange,提问作者Atreides
相关产品推荐
相关产品推荐

