You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 21:20:25