Nodejs http.request 报错 Parse error

Nodejs http.request 报错 Parse error

用nodejs 做客户端向别的服务器发送请求的时候 如果别的服务器的响应码是自定义的 而不是默认的, 比如说会出现20000的响应码 这种报错怎末解决
exports.get = function(req, res){ var data = ‘<Request>’+ ’ <Id>’+‘11’+’</Id>’+ ’</Request>’ var opt = { method: “POST”, host: interfaceConfig.emallServer, port: interfaceConfig.emallPort, path: interfaceConfig.emallUser, headers: { “Content-Type”: ‘text/xml’, “Content-Length”: data.length } }; var request = http.request(opt, function (serverFeedback) { serverFeedback.setEncoding(‘utf8’); serverFeedback.on(‘data’, function (data) { console.log(data); }); }); request.write(data + “\n”); request.end(); }; 报错: Error :Parse Error at Socket.socketOnData (http.js :1583:20) at Tcp.onread(net.js:527:27) 自己抓包看了 响应码是20004但没有响应描述 报错如上 这种问题怎么解决啊 POST /emall/interface/getUserInfoByToken HTTP/1.1

Content-Type: text/xml

Content-Length: 48

Host: 211.140.7.142

Connection: keep-alive

<Request> <Id>11</Id></Request> HTTP/1.1 20004

Server: Apache-Coyote/1.1

Set-Cookie: JSESSIONID=C8DEB8E76971731937CCF9CCA9D01B39; Path=/emall/; HttpOnly

Content-Length: 0

Date: Thu, 15 May 2014 03:10:30 GMT


4 回复

对于这个问题,http.request 在处理非标准HTTP状态码(例如 20004)时可能会遇到解析错误。这是因为 Node.js 默认的HTTP模块只支持标准的状态码。为了解决这个问题,你可以手动处理这些非标准状态码。

以下是一个示例代码,展示了如何处理这种场景:

const http = require('http');

exports.get = function(req, res) {
    var data = '<Request>' +
               '<Id>11</Id>' +
               '</Request>';
    
    var opt = {
        method: "POST",
        host: '211.140.7.142',
        port: 80,
        path: '/emall/interface/getUserInfoByToken',
        headers: {
            "Content-Type": 'text/xml',
            "Content-Length": Buffer.byteLength(data)
        }
    };

    var request = http.request(opt, function(serverFeedback) {
        let responseData = '';

        serverFeedback.setEncoding('utf8');
        serverFeedback.on('data', function(chunk) {
            responseData += chunk;
        });

        serverFeedback.on('end', function() {
            console.log('Response Data:', responseData);

            // 检查自定义状态码并进行相应处理
            if (serverFeedback.statusCode === 20004) {
                console.log('Custom status code received:', serverFeedback.statusCode);
                // 在这里添加你的错误处理逻辑
            } else if (serverFeedback.statusCode >= 200 && serverFeedback.statusCode < 300) {
                // 处理成功的情况
                console.log('Success response received:', serverFeedback.statusCode);
                res.send(responseData);
            } else {
                console.error('Unexpected status code:', serverFeedback.statusCode);
                res.status(serverFeedback.statusCode).send(responseData);
            }
        });
    });

    request.on('error', function(e) {
        console.error(`Problem with request: ${e.message}`);
    });

    request.write(data);
    request.end();
};

解释

  1. 数据编码:使用 Buffer.byteLength(data) 来计算 Content-Length,而不是 data.length
  2. 响应处理:通过监听 data 事件收集所有响应数据,并在 end 事件中处理最终结果。
  3. 自定义状态码处理:在 end 事件中检查 statusCode 是否为 20004,并根据需要进行处理。
  4. 错误处理:添加了对请求错误的处理。

这样可以确保你能够正确地处理非标准HTTP状态码,并且不会因为解析错误而中断程序执行。


比较奇怪的设计. 好像nodejs的http没戏(不确定), 底层http parser报的错:

// deps/http_parser/http_parser.c
if (parser->status_code > 999) {       // 如果自定义的状态码,超过了999, 直接报错 ==> 没有超过的话, 仍然是可接受的
  SET_ERRNO(HPE_INVALID_STATUS);
  goto error;
}
// lib/http.js
var ret = parser.execute(d, start, end - start);
  if (ret instanceof Error) {
    debug('parse error');
    freeParser(parser, req);
    socket.destroy();
    req.emit('error', ret);
    req._hadError = true;
  }

照这样来看, 走 Socket 应该是行得通的, 只是很麻烦(麻烦到几乎自己要实现部分HTTP协议):

var net = require('net');
var client = net.connect({port: your_port, host:'your_host'},
    function() { //'connect' listener
      console.log('client connected');
      client.write('GET / HTTP/1.1\r\n\r\n');   // 模拟 HTTP请求
});

client.on(‘data’, function(data) { console.log(data.toString()); // 响应来了, 还要解析 — 工作量巨增 client.end(); }); client.on(‘end’, function() { console.log(‘client disconnected’); });

其它方法未知, 可能存在更容易的做法(修改nodejs源码, 再编译?).

20000,蛋疼的状态码。。。

根据你的描述,问题在于服务器返回了一个非标准的状态码(例如20004),而Node.js的http.request在处理这种非标准状态码时可能会抛出“Parse Error”。

你可以通过捕获错误并处理来解决这个问题。以下是修改后的示例代码:

const http = require('http');

exports.get = function(req, res) {
    var data = '<Request><Id>11</Id></Request>';
    var opt = {
        method: "POST",
        host: interfaceConfig.emallServer,
        port: interfaceConfig.emallPort,
        path: interfaceConfig.emallUser,
        headers: {
            "Content-Type": 'text/xml',
            "Content-Length": Buffer.byteLength(data)
        }
    };

    const request = http.request(opt, function(serverFeedback) {
        serverFeedback.setEncoding('utf8');
        let responseBody = '';
        serverFeedback.on('data', function(chunk) {
            responseBody += chunk;
        });
        serverFeedback.on('end', function() {
            console.log(responseBody);
            // 在这里处理响应数据
        });
    });

    request.on('error', function(e) {
        console.error(`Problem with request: ${e.message}`);
    });

    request.write(data);
    request.end();
};

解释

  1. 请求配置:确保请求头中的Content-Length使用正确的值,使用Buffer.byteLength而不是直接使用字符串长度。
  2. 错误处理:通过监听request对象的error事件来捕获并处理错误。
  3. 响应处理:将响应体拼接起来以便完整地获取响应内容。

这样即使服务器返回一个非标准的状态码,Node.js也不会立即抛出错误,并且你可以根据需要处理响应内容。

回到顶部