您现在的位置是:亿华云 > 数据库

Node.js HTTP 解析器 llhttp 的使用

亿华云2025-10-03 01:18:50【数据库】0人已围观

简介llhttp 是 Node.js 的 HTTP 1.1 解析器,用于替代早期的http_parser,性能上有了非常大的提升,最近打算在 No.js 里引入 llhttp 来处理 HTTP 协议的解析

llhttp 是解析 Node.js 的 HTTP 1.1 解析器,用于替代早期的使用http_parser,性能上有了非常大的解析提升,最近打算在 No.js 里引入 llhttp 来处理 HTTP 协议的使用解析,本文简单介绍一下如何使用。解析

llhttp 项目是使用 Node.js 中的子项目,地址在:

https://github.com/nodejs/llhttp。解析

使用步骤如下:

1. 安装 npx:npm i npx -g

2. 执行 ts 生成 c 代码:npx ts-node bin/generate.ts,使用或者执行 make generate

3. 这时候build 目录下生成了 llhttp.h 和 llhttp.c,解析再加上 native 下的使用 c 代码,亿华云就是解析 llhttp 的全部代码,我们可以把他复制到自己的使用项目中使用

下面看看如何使用。llhttp 使用回调钩子的解析设计思想,初始化解析器的使用时候,我们可以设置解析类型,解析是请求或响应报文,然后设置解析状态的回调,比如解析道 URL 时回调,解析到 header 时回调。接着传入报文执行 llhttp_execute 就可以,服务器托管下面是解析请求报文的例子。

#include <stdio.h> #include <string.h> #include "llhttp.h" #define MAX_LEN 2048 int on_message_begin(llhttp_t* parser){      printf("parse start\n");     return 0; } int on_url(llhttp_t* parser, const char* at, size_t length){      char url[MAX_LEN];     strncpy(url, at, length);     url[length] = \0;     printf("on_url: %s\n", url);     return 0; } int on_header_field(llhttp_t* parser, const char* at, size_t length){      char header_field[MAX_LEN];     strncpy(header_field, at, length);     header_field[length] = \0;     printf("head field: %s\n", header_field);     return 0; } int on_header_value(llhttp_t* parser, const char* at, size_t length){      char header_value[MAX_LEN];     strncpy(header_value, at, length);     header_value[length] = \0;     printf("head value: %s\n", header_value);     return 0; } int on_headers_complete(llhttp_t* parser){      printf("on_headers_complete, major: %d, major: %d, keep-alive: %d, upgrade: %d\n", parser->http_major, parser->http_minor, llhttp_should_keep_alive(parser), parser->upgrade);     return 0; } int on_body(llhttp_t* parser, const char* at, size_t length){      char body[MAX_LEN];     strncpy(body, at, length);     body[length] = \0;     printf("on_body: %s\n", body);     return 0; } int on_message_complete(llhttp_t* parser){      printf("on_message_complete\n");     return 0; } int main(){      llhttp_t parser;     llhttp_settings_t settings;     llhttp_settings_init(&settings);     llhttp_init(&parser, HTTP_REQUEST, &settings);     settings.on_message_begin = on_message_begin;     settings.on_url = on_url;     settings.on_header_field = on_header_field;     settings.on_header_value = on_header_value;     settings.on_headers_complete = on_headers_complete;     settings.on_body = on_body;     settings.on_message_complete = on_message_complete;     const char* request = "POST /index.html HTTP/1.1\r\nconnection:close\r\ncontent-length: 1\r\n\r\n1\r\n\r\n";     int request_len = strlen(request);     enum llhttp_errno err = llhttp_execute(&parser, request, request_len);     if (err != HPE_OK) {          fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err),         parser.reason);     }     return 0; } 

接着看解析响应的例子。

#include <stdio.h> #include <string.h> #include "llhttp.h" #define MAX_LEN 2048 int on_message_begin(llhttp_t* parser){      printf("parse start\n");     return 0; } int on_url(llhttp_t* parser, const char* at, size_t length){      char url[MAX_LEN];     strncpy(url, at, length);     url[length] = \0;     printf("on_url: %s\n", url);     return 0; } int on_status(llhttp_t* parser, const char* at, size_t length){      char status[MAX_LEN];     strncpy(status, at, length);     status[length] = \0;     printf("on_status: %s\n", status);     return 0; } int on_header_field(llhttp_t* parser, const char* at, size_t length){      char header_field[MAX_LEN];     strncpy(header_field, at, length);     header_field[length] = \0;     printf("head field: %s\n", header_field);     return 0; } int on_header_value(llhttp_t* parser, const char* at, size_t length){      char header_value[MAX_LEN];     strncpy(header_value, at, length);     header_value[length] = \0;     printf("head value: %s\n", header_value);     return 0; } int on_headers_complete(llhttp_t* parser){      printf("on_headers_complete, major: %d, major: %d, keep-alive: %d, upgrade: %d\n", parser->http_major, parser->http_minor, llhttp_should_keep_alive(parser), parser->upgrade);     return 0; } int on_body(llhttp_t* parser, const char* at, size_t length){      char body[MAX_LEN];     strncpy(body, at, length);     body[length] = \0;     printf("on_body: %s\n", body);     return 0; } int on_message_complete(llhttp_t* parser){      printf("on_message_complete\n");     return 0; } int main(){      llhttp_t parser;     llhttp_settings_t settings;     llhttp_settings_init(&settings);     llhttp_init(&parser, HTTP_RESPONSE, &settings);     settings.on_message_begin = on_message_begin;     settings.on_url = on_url;     settings.on_status = on_status;     settings.on_header_field = on_header_field;     settings.on_header_value = on_header_value;     settings.on_headers_complete = on_headers_complete;     settings.on_body = on_body;     settings.on_message_complete = on_message_complete;     const char* reponse = "HTTP/1.1 200 OK\r\nServer: nginx\r\ncontent-length: 11\r\n\r\nhello:world\r\n\r\n";     int reponse_len = strlen(reponse);     enum llhttp_errno err = llhttp_execute(&parser, reponse, reponse_len);     if (err != HPE_OK) {          fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err),         parser.reason);     }     return 0; } 

llhttp 目前支持以下钩子回调。

struct llhttp_settings_s {    /* Possible return values 0, -1, `HPE_PAUSED` */   llhttp_cb      on_message_begin;   /* Possible return values 0, -1, HPE_USER */   llhttp_data_cb on_url;   llhttp_data_cb on_status;   llhttp_data_cb on_header_field;   llhttp_data_cb on_header_value;   /* Possible return values:    * 0  - Proceed normally    * 1  - Assume that request/response has no body, and proceed to parsing the    *      next message    * 2  - Assume absence of body (as above) and make `llhttp_execute()` return    *      `HPE_PAUSED_UPGRADE`    * -1 - Error    * `HPE_PAUSED`    */   llhttp_cb      on_headers_complete;   /* Possible return values 0, -1, HPE_USER */   llhttp_data_cb on_body;   /* Possible return values 0, -1, `HPE_PAUSED` */   llhttp_cb      on_message_complete;   /* When on_chunk_header is called, the current chunk length is stored    * in parser->content_length.    * Possible return values 0, -1, `HPE_PAUSED`    */   llhttp_cb      on_chunk_header;   llhttp_cb      on_chunk_complete;   /* Information-only callbacks, return value is ignored */   llhttp_cb      on_url_complete;   llhttp_cb      on_status_complete;   llhttp_cb      on_header_field_complete;   llhttp_cb      on_header_value_complete;}; 

我们也可以以静态库或动态库的方式使用 llhttp。执行 make all 就会在 build 目录下生成静态和动态库,我们把头文件 llhttp.h 和 静态库或动态库复制到自己项目里使用就可以,编译的时候加上 -lllhttp -L.。

总结:llhttp 的使用上还算比较简单清晰,如果我们项目里需要解析 HTTP 协议的话可以试试,使用 demo 可以参考 https://github.com/theanarkh/llhttp-demo。源码库

很赞哦!(7)