如何解析http报文

Mar*_*arc 5 parsing message http node.js

我正在寻找 Node.js 中解析 http 消息的本机方法。无论消息来自何处,简单的硬编码字符串或通过网络 tcp/udp 或被视为“套接字”的自定义双工流。

作为搜索结果,我只发现过时的答案,process.binding而不是现有的私有属性/方法。

使用内置模块解析传入的 http 消息的“正确”方法是什么?

(作为评论,我接受任何提示/包,但目标应该是仅使用节点模块中的构建)

提前致谢。

sle*_*man 5

如果我从一个故事开始,我希望你能原谅我……它提供了一些背景信息。

很久以前(大约 2001/2002 年)我决定需要了解更多有关 Web 编程的知识。我已经知道如何编写 HTML 并将其加载到浏览器中。我听说过这个叫做 CGI 的东西,但它需要我安装一个服务器..我认为我没有时间学习。因此,凭借我的学士学位和一两年的“专业”编程经验,我认为显而易见的事情就是学习 HTTP 的工作原理。

所以我开始阅读 HTTP RFC:https://www.rfc-editor.org/rfc/rfc2616

事实证明,HTTP 确实很简单,但有很多细节......其中大部分都是可选的。我需要一种方法来知道我可以忽略什么以及我必须实现什么,因为我没有时间实现完整的规范(我有一份日常工作要做)。谷歌几年前才问世(太晚了,无法帮助我在大学完成论文,但正好赶上了我的第一份工作),所以我想我应该谷歌“最小的http实现”。如今,您可能会得到不同的结果,但当时它给了我詹姆斯·马歇尔 (James Marshall) 的出色的《HTTP 变得非常简单》(今天仍然在线)。

因此,您要寻找的答案是阅读“HTTP 让一切变得非常简单”页面

总长DR

由于 stackoverflow 的政策,我只给你留下一个链接是不礼貌的。不过我仍然强烈建议你阅读那篇文章。无论如何,这是 TLDR:

  1. HTTP 请求只是纯文本。它的简单格式为:

    Request Line
    Header
    Header
    Header
    
    Run Code Online (Sandbox Code Playgroud)
  2. HTTP 请求的每个部分都用换行符分隔

注意:从技术上讲,它们应该是\r\n,但强烈建议您也接受\n作为换行符。

  1. HTTP 请求由两个换行符终止

注意:从技术上讲,它们应该是 4 字节:\r\n\r\n但强烈建议您也接受 2 字节终止符:\n\n

  1. 请求行的格式为:

     METHOD path PROTOCOL_VERSION
    
    Run Code Online (Sandbox Code Playgroud)

    METHOD 是 HTTP 方法,例如 POST、GET、PUT、DELETE 等。通常它们应该是大写的。

    该路径是通常预期为您请求的文件的路径的 url 路径,但在更现代的情况下,更通常是由 Web 框架处理的端点。

    协议版本的格式为:

     HTTP/1.1
    
    Run Code Online (Sandbox Code Playgroud)

    通常你可以忽略这一点。

  2. 请求行的各个部分由空格字符分隔。从技术上讲,应该只有一个空格,尽管我见过发送多个空格的格式严重错误的请求。浏览器绝不会发送多个空格。

  3. 标头的格式为:

     Header-name: header value
    
    Run Code Online (Sandbox Code Playgroud)
  4. 标题名称可以是标题大写或小写或混合,所有这些都是有效的。

知道了这一点,解析 HTTP 实际上相当简单:

// Pseudocode:

let headers = {};
let method = '';
let path = '';

while (1) {
    input = read();

    buffer.append(input);

    if (buffer.contains('\n\n') || buffer.contains('\r\n\r\n') {
        raw_request = buffer.split('\n');
        request_line = raw_request[0].split(' ');
        method = request_line[0];
        path = request_line[1];

        for (let i=1; i<raw_request.length; i++) {
            let header = raw_request[i].split(':');
            headers[header[0].toLowerCase()] = header.slice(1).join(':');
        }
        break
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,您不应该使用阻塞while循环来读取 JavaScript 中的表单 I/O,因为它不起作用,但您已经了解了总体思路。

您还需要处理其他事情,例如读取Content-Length标头以确定 POST 请求何时完成、如何解析 POST 表单数据(大多数 js 框架不这样做 - 它们要求您使用额外的模块来解析请求) body) 等,但这应该让您从一个最小可行的实现开始,您可以继续添加功能以处理所有不同的请求类型。