You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ExpressJS如何解析请求体二进制上传数据获取Buffer对象

Express处理纯二进制流文件上传实现方案

问题背景

当前前端上传逻辑不使用multipart/form-data格式,直接将文件二进制内容作为POST请求体发送,文件扩展名通过自定义请求头File-Extension传输,需要在Express服务端获取完整请求体的Buffer实例,最终保存为文件名随机、后缀匹配上传扩展名的本地文件。

前端参考实现

document.querySelector("form").onsubmit = e => {
  e.preventDefault();
  const input = document.querySelector("input"),
   files = input.files;
   
  if(files.length > 0) {
    const ext = input.value.split("/").pop().split(".").pop();
    fetch("https://example.com/fileUpload", {
      method: "POST",
      headers: {
        "File-Extension": "." + ext
      },
      body: files[0]
    })
  }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>文件上传</title>
</head>
<body>
  <form>
    上传文件<input type="file">
    <input type="submit" value="upload">
  </form>
</body>
</html>

具体实现方案

平时用来解析JSON、文本请求的body-parser本身就内置了原始二进制解析能力,不需要额外引入multer等专门处理multipart/form-data的上传中间件,解析完成后可以直接拿到完整的Buffer实例。Express 4.16.0及以上版本甚至不需要单独安装body-parser,框架本身内置了同款express.raw()中间件可以直接使用。

实现步骤

  • 注册二进制解析中间件,配置匹配的请求类型和上传大小上限
    const express = require('express');
    const fs = require('fs/promises');
    const crypto = require('crypto');
    const path = require('path');
    
    const app = express();
    
    // 注册raw解析中间件,所有请求的二进制内容会被自动拼接为Buffer挂载到req.body
    app.use(express.raw({
      type: '*/*', // 匹配所有Content-Type的请求
      limit: '100mb' // 根据业务需求调整最大允许上传的文件大小
    }));
    
  • 编写上传接口逻辑,读取扩展名、生成随机文件名、写入本地存储
    app.post('/fileUpload', async (req, res) => {
      try {
        // req.body 就是完整的文件二进制Buffer实例
        const fileBuffer = req.body;
        
        // 读取请求头中的扩展名,做安全校验过滤非法字符,防止路径遍历攻击
        let ext = req.get('File-Extension') || '';
        ext = ext.replace(/[^.a-zA-Z0-9]/g, '');
        if (!ext.startsWith('.')) ext = '.' + ext;
    
        // 生成随机文件名,避免重名
        const saveFileName = crypto.randomUUID() + ext;
        const saveDir = path.join(__dirname, 'upload');
        const savePath = path.join(saveDir, saveFileName);
    
        // 存储目录不存在时自动创建
        await fs.mkdir(saveDir, { recursive: true });
        // 将Buffer写入本地文件
        await fs.writeFile(savePath, fileBuffer);
    
        res.json({
          code: 0,
          msg: '上传成功',
          data: { fileName: saveFileName }
        })
      } catch (err) {
        res.status(500).json({
          code: 500,
          msg: '上传失败',
          error: err.message
        })
      }
    })
    
    app.listen(3000, () => {
      console.log('服务启动在3000端口');
    })
    

注意事项

  • 必须手动配置limit参数,Express/body-parser默认的请求体大小上限仅为100kb,无法满足常规文件上传需求。
  • 从请求头获取的扩展名必须做非法字符过滤,避免攻击者传入../等特殊字符触发路径遍历漏洞,将文件写入非预期目录。
  • 如果不想使用内置中间件,也可以手动监听请求对象的data事件接收数据块、end事件拼接完整Buffer,但生产环境直接使用官方维护的内置中间件更稳妥,已经处理好了断流、超限等边界情况。

内容的提问来源于stack exchange,提问作者c136

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 21:27:22