【问题标题】:node.js create object from raw http request stringnode.js 从原始 http 请求字符串创建对象
【发布时间】:2022-01-11 11:57:26
【问题描述】:

我有一个原始的 HTTP 请求字符串,我需要从中创建一个对象表示。

我没有重新发明轮子,而是考虑使用内部 http 解析器来获取 http.IncomingMessage 的实例

有可能吗?

我认为是因为字符串与完整的流没有太大区别。

怎么做?

我查看了源代码,他们得到了一个请求解析器,如下所示

var HTTPParser = process.binding('http_parser').HTTPParser;
var parser = new HTTPParser(HTTPParser.REQUEST)

编辑

node.js test 的一些进展

var request = Buffer(raw);
var parser = new HTTPParser(HTTPParser.REQUEST);

parser.execute(request, 0, request.length);

编辑 2

缺少一些事件处理程序(全部)

parser.onHeadersComplete = function(res) {
    console.log('onHeadersComplete');
    console.log(res);
};

parser.onBody = function(body) {
    console.log('body done');
    console.log(body.toString());
}

parser.onMessageComplete = function(res) {
    console.log('done');
};

谢谢

【问题讨论】:

  • 我更新了我的问题。我有一个“GET / HTTP/1.1\nHost: localhost\n\n”字符串,我需要对其进行解析以创建一个对象。结果对象必须是 http.IncomingMessage 的实例
  • 那么问题到底是什么?
  • 获取 IncomingMessage 对象之前的完整工作流程。
  • 为什么不使用http 模块? require('http').createServer(function(req,res){ ... }) 每次有请求时都会调用该函数。 req 已经是 http.IncomingMessage 的实例
  • 我不需要 HTTP 服务器来处理请求。我只是做一个 HTTP 消息的解析器。

标签: node.js parsing http


【解决方案1】:

显然,http_parser 模块是一个基于回调的低级解析器。它会通过这些回调将它可以解析的字符串的任何部分发送给您,并且您可以创建IncomingMessage 或您需要的任何其他内容。

我相信您可能正在寻找类似的东西:

var HTTPParser = process.binding('http_parser').HTTPParser;

function parseMessage(request) {
    var _message = {};
    var _parser = new HTTPParser(HTTPParser.REQUEST);

    _parser.onHeadersComplete = function(headers) { 
        _message = headers; 
    }

    _parser.onBody = function(body, start, len) {
        _message.data = body.slice(start, start+len);
    }

    var _result = _parser.execute(request, 0, request.length);

    if (_result != request.length) { 
        _message.error = _result; 
    }
    else {
        _message.error = false;
    }
    return _message;
}

var request = Buffer("GET / HTTP/1.1\nHost: localhost\nContent-Length: 2\n\nHi\n\n");
result = parseMessage(request);

请注意,特定的IncomingMessage 类使用socket 参数化,并且通常围绕它在服务器中使用的想法构建。 code for parsing it 按原样重复使用有点混乱(按我的口味)。

【讨论】:

  • 最近的节点版本改变了接口,现在回调分配像parser[HTTPParser.kOnHeaders] = function() {...}
【解决方案2】:

老话题,但我想说点什么。

在自己的东西(模块或应用程序)中导出 HTTPParser 并不那么简单,因为 http 库使用了许多内部本地函数和构造函数。此外,HTTPParser 本身是从 C 库和一些助手中绑定的。

据我所知,http.parsers 已从 Node > 4 中删除,因此唯一的方法是从 http 库中导入所有必要的东西。

对于节点 0.x,有很简单的导入方法:

var parser = require("http").parsers.alloc();

parser.onIncoming = function(response) {
  console.log(response);
};

function parse(data) {
    var buffer = new Buffer(data);
    parser.execute(buffer, 0, buffer.length);
}
/**
 * tests
 */
parse("DELETE / HTTP/1.1\r\n");
parse("user-agent: curl\r\n");
parse("x-pingback:");
parse("12023\r\n");
parse("\r\n");

//response
{ _readableState: 
   { highWaterMark: 16384,
     buffer: [],
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: false,
     ended: false,
     endEmitted: false,
     reading: false,
     calledRead: false,
     sync: true,
     needReadable: false,
     emittedReadable: false,
     readableListening: false,
     objectMode: false,
     defaultEncoding: 'utf8',
     ranOut: false,
     awaitDrain: 0,
     readingMore: false,
     decoder: null,
     encoding: null },
  readable: true,
  domain: null,
  _events: {},
  _maxListeners: 10,
  socket: undefined,
  connection: undefined,
  httpVersion: '1.1',
  complete: false,
  headers: { 'user-agent': 'curl', 'x-pingback': '12023' },
  trailers: {},
  _pendings: [],
  _pendingIndex: 0,
  url: '/',
  method: 'DELETE',
  statusCode: null,
  client: undefined,
  _consuming: false,
  _dumped: false,
  httpVersionMajor: 1,
  httpVersionMinor: 1,
  upgrade: false }

更多信息here

另外,感谢@KT 提供优雅的解决方案

【讨论】:

  • 是否有针对较新节点版本的解决方案,例如当前的 LTS (v16)? require("http").parsers 未定义。
【解决方案3】:

手动解析呢?以下是从缓冲区解析 http 请求的示例。需要先将字符串转换成缓冲区。

const data = Buffer.from([80, 79, 83, 84, 32, 104, 116, 116, 112, 58, 47, 47, 108, 111, 99, 97, 108, 104, 111, 115, 116, 58, 49, 50, 51, 52, 47, 104, 101, 108, 108, 111, 32, 72, 84, 84, 80, 47, 49, 46, 49, 13, 10, 72, 111, 115, 116, 58, 32, 108, 111, 99, 97, 108, 104, 111, 115, 116, 58, 49, 50, 51, 52, 13, 10, 85, 115, 101, 114, 45, 65, 103, 101, 110, 116, 58, 32, 99, 117, 114, 108, 47, 55, 46, 55, 56, 46, 48, 13, 10, 65, 99, 99, 101, 112, 116, 58, 32, 42, 47, 42, 13, 10, 80, 114, 111, 120, 121, 45, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 58, 32, 75, 101, 101, 112, 45, 65, 108, 105, 118, 101, 13, 10, 67, 111, 110, 116, 101, 110, 116, 45, 76, 101, 110, 103, 116, 104, 58, 32, 55, 13, 10, 67, 111, 110, 116, 101, 110, 116, 45, 84, 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 120, 45, 119, 119, 119, 45, 102, 111, 114, 109, 45, 117, 114, 108, 101, 110, 99, 111, 100, 101, 100, 13,10, 13, 10, 97, 61, 49, 38, 98, 61, 50]);


const delimIndex = data.indexOf('\r\n\r\n');
const lines = data.slice(0, delimIndex).toString('utf8').split('\r\n');
const startLine = lines[0];
const headers = lines.slice(1);
const body=data.slice(delimIndex + 4);

console.log(`${startLine}\n\n${headers.join('\n')}\n\n${body}`);

【讨论】:

    猜你喜欢
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 2022-01-14
    • 2012-04-17
    • 2015-09-08
    相关资源
    最近更新 更多