Project Icon

multipart-parser

跨平台高效的JavaScript multipart解析器

multipart-parser是一款快速高效的JavaScript multipart解析器,可在任何JavaScript环境中运行。它支持处理文件上传、解析multipart/mixed消息和电子邮件附件等多种场景。该项目支持所有multipart/*类型,在保持高性能的同时最小化内存使用。通过简洁的API,multipart-parser适用于Node.js、Bun和Deno等多种JavaScript运行时环境。

multipart-parser

multipart-parser 是一个快速、高效的多部分流解析器。它可以在任何 JavaScript 环境中使用(不仅限于 node.js),适用于多种场景,包括:

  • 处理文件上传(multipart/form-data 请求)
  • 解析 multipart/mixed 消息(电子邮件附件、API 响应等)
  • 解析同时包含纯文本和 HTML 版本的电子邮件消息(multipart/alternative

目标

本项目的目标是:

  • 提供一个可在任何 JavaScript 运行环境中使用的多部分解析器
  • 支持全系列 multipart/* 消息类型
  • 在使用尽可能少内存的同时,保持足够快的处理速度

安装

npm 安装:

npm install @mjackson/multipart-parser

或从 JSR 安装:

deno add @mjackson/multipart-parser

使用方法

multipart-parser 最常见的用途是在构建 Web 服务器时处理文件上传。对于这种情况,parseMultipartRequest 函数是你的好帮手。它会自动验证请求是否为 multipart/form-data,从 Content-Type 头部提取多部分边界,解析 request.body 流中的所有字段和文件,并将每个部分作为 MultipartPart 对象 yield 给你,以便你可以将其保存到磁盘或上传到其他地方。

import { MultipartParseError, parseMultipartRequest } from '@mjackson/multipart-parser';

async function handleMultipartRequest(request: Request): void {
  try {
    // 解析器会在每个 MultipartPart 可用时 `yield` 它
    for await (let part of parseMultipartRequest(request)) {
      console.log(part.name);
      console.log(part.filename);

      if (/^text\//.test(part.mediaType)) {
        console.log(await part.text());
      } else {
        // TODO: part.body 是一个 ReadableStream<Uint8Array>,将其流式传输到文件
      }
    }
  } catch (error) {
    if (error instanceof MultipartParseError) {
      console.error('解析多部分请求失败:', error.message);
    } else {
      console.error('发生意外错误:', error);
    }
  }
}

主模块(import from "@mjackson/multipart-parser")假设你正在使用 fetch APIRequestReadableStream 等)。Node.js 在 16.5.0 版本 中通过 undici 项目添加了对这些接口的支持。

但是,如果你正在为 Node.js 构建依赖于特定 node API 的服务器,如 http.IncomingMessagestream.Readablebuffer.Buffer(类似于 Express 或 http.createServer),multipart-parser 还提供了一个额外的模块,可直接与这些 API 配合使用。

import * as http from 'node:http';

import { MultipartParseError } from '@mjackson/multipart-parser';
// 注意:从 multipart-parser/node 导入以使用 node 特定的 API
import { parseMultipartRequest } from '@mjackson/multipart-parser/node';

const server = http.createServer(async (req, res) => {
  try {
    for await (let part of parseMultipartRequest(req)) {
      console.log(part.name);
      console.log(part.filename);
      console.log(part.mediaType);

      // ...
    }
  } catch (error) {
    if (error instanceof MultipartParseError) {
      console.error('解析多部分请求失败:', error.message);
    } else {
      console.error('发生意外错误:', error);
    }
  }
});

server.listen(8080);

底层 API

如果你直接处理多部分边界和不一定属于请求的多部分数据缓冲区/流,multipart-parser 提供了一些你可以直接使用的底层 API:

import { parseMultipart } from '@mjackson/multipart-parser';

// 从某个 API、文件系统等获取数据
let multipartMessage = new Uint8Array();
// 也可以是流或任何 Iterable/AsyncIterable
// let multipartData = new ReadableStream(...);
// let multipartData = [new Uint8Array(...), new Uint8Array(...)];

let boundary = '----WebKitFormBoundary56eac3x';

for await (let part of parseMultipart(multipartMessage, boundary)) {
  // 对 part 进行任何你想要的操作...
}

如果你更喜欢基于回调的 API,可以实例化你自己的 MultipartParser 并使用它:

import { MultipartParser } from '@mjackson/multipart-parser';

let multipartMessage = new Uint8Array(); // 或 ReadableStream<Uint8Array>
let boundary = '...';

let parser = new MultipartParser(boundary);

// parser.parse() 将在所有回调完成后解析
await parser.parse(multipartMessage, async (part) => {
  // 执行你需要的操作...
});

示例

examples 目录包含了几个如何使用这个库的工作示例:

基准测试

multipart-parser 设计为尽可能高效,仅对数据流进行操作,在常见用法中从不缓冲。这种设计在处理任何大小的多部分负载时都能产生卓越的性能。在大多数基准测试中,multipart-parser 的速度与 busboy 一样快或更快。

重要提示:基准测试可能比较棘手,结果会因平台、参数和其他因素而有很大差异。因此,请谨慎看待这些结果。这个库的主要目的是在 JavaScript 运行时之间保持可移植性。为此,我们在三个主要的开源 JavaScript 运行时上运行基准测试:Node.js、Bun 和 Deno。这些基准测试仅用于表明 multipart-parser 在任何运行环境中都能快速完成工作。

在我的笔记本电脑上运行基准测试的结果:

> @mjackson/multipart-parser@0.4.2 bench:node /Users/michael/Projects/multipart-parser
> node --import tsimp/import ./bench/runner.ts

平台:Darwin (23.5.0) CPU:Apple M1 Pro 日期:2024年8月13日,下午6:47:34 Node.js v22.1.0 ┌──────────────────┬──────────────────┬──────────────────┬──────────────────┬───────────────────┐ │ (索引) │ 1个小文件 │ 1个大文件 │ 100个小文件 │ 5个大文件 │ ├──────────────────┼──────────────────┼──────────────────┼──────────────────┼───────────────────┤ │ multipart-parser │ '0.01 ms ± 0.08' │ '1.17 ms ± 0.27' │ '0.12 ms ± 0.03' │ '10.94 ms ± 0.24' │ │ busboy │ '0.03 ms ± 0.08' │ '3.00 ms ± 0.09' │ '0.21 ms ± 0.03' │ '30.10 ms ± 2.73' │ │ @fastify/busboy │ '0.02 ms ± 0.07' │ '1.19 ms ± 0.07' │ '0.38 ms ± 0.07' │ '12.15 ms ± 2.30' │ └──────────────────┴──────────────────┴──────────────────┴──────────────────┴───────────────────┘

@mjackson/multipart-parser@0.4.2 bench:bun /Users/michael/Projects/multipart-parser bun run ./bench/runner.ts

平台:Darwin (23.5.0) CPU:Apple M1 Pro 日期:2024年8月13日,下午6:49:45 Bun 1.1.21 ┌──────────────────┬────────────────┬────────────────┬─────────────────┬─────────────────┐ │ │ 1个小文件 │ 1个大文件 │ 100个小文件 │ 5个大文件 │ ├──────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┤ │ multipart-parser │ 0.01 ms ± 0.07 │ 0.95 ms ± 0.12 │ 0.13 ms ± 0.09 │ 9.13 ms ± 0.29 │ │ busboy │ 0.03 ms ± 0.10 │ 3.55 ms ± 0.10 │ 0.35 ms ± 0.17 │ 35.54 ms ± 2.57 │ │ @fastify/busboy │ 0.04 ms ± 0.10 │ 7.17 ms ± 0.10 │ 0.62 ms ± 0.13 │ 71.99 ms ± 3.01 │ └──────────────────┴────────────────┴────────────────┴─────────────────┴─────────────────┘

@mjackson/multipart-parser@0.4.2 bench:deno /Users/michael/Projects/multipart-parser deno --unstable-byonm --unstable-sloppy-imports run --allow-sys ./bench/runner.ts

平台:Darwin (23.5.0) CPU:Apple M1 Pro 日期:2024年8月13日,下午6:52:51 Deno 1.45.5 ┌──────────────────┬──────────────────┬───────────────────┬──────────────────┬────────────────────┐ │ (索引) │ 1个小文件 │ 1个大文件 │ 100个小文件 │ 5个大文件 │ ├──────────────────┼──────────────────┼───────────────────┼──────────────────┼────────────────────┤ │ multipart-parser │ "0.02 ms ± 0.18" │ "1.18 ms ± 1.07" │ "0.10 ms ± 0.43" │ "11.00 ms ± 1.18" │ │ busboy │ "0.04 ms ± 0.27" │ "3.02 ms ± 1.00" │ "0.29 ms ± 0.71" │ "30.22 ms ± 2.61" │ │ @fastify/busboy │ "0.05 ms ± 0.31" │ "12.32 ms ± 0.73" │ "0.77 ms ± 0.97" │ "125.04 ms ± 8.39" │ └──────────────────┴──────────────────┴───────────────────┴──────────────────┴────────────────────┘

我鼓励你自己运行这些基准测试。你可能会得到不同的结果!

pnpm run bench

致谢

感谢Jacob Ebey在发布前对这个项目进行了多次代码审查。

许可证

请参阅LICENSE

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号