Hapi.js 文件上传完全指南

Hapi.js 以配置驱动处理文件上传:payload 选项控制解析行为与大小限制。本文讲解单/多文件上传、流式写盘、文件校验与进度追踪的生产级实现。

最佳实践
应用接口与数据存储连接插画

Hapi 的文件上传通过路由的 payload 配置完成:output: 'stream' 拿到流、maxBytes 限制大小、parse: true 自动解析 multipart。流式写盘(pipe 到 fs)是内存安全的关键,所有大小与类型限制都在路由配置里声明——这正是 Hapi 配置驱动哲学的体现。

Hapi 的 payload 哲学

Hapi 把请求体的处理收进路由配置:解析方式(stream/data/file)、大小上限、超时、多部分行为全部声明式。文件上传的安全基线因此写在路由定义里,一眼可审计。

基础上传实现

const Hapi = require('@hapi/hapi');
const fs = require('fs');
const path = require('path');
const { pipeline } = require('stream/promises');

const server = Hapi.server({ port: 3000 });

server.route({
  method: 'POST',
  path: '/upload',
  options: {
    payload: {
      output: 'stream',          // 流式获取文件
      parse: true,               // 解析 multipart
      maxBytes: 10 * 1024 * 1024, // 10MB 上限
      multipart: true,
    },
  },
  handler: async (request, h) => {
    const file = request.payload.file;

    const filename = `${Date.now()}-${path.basename(file.hapi.filename)}`;
    await pipeline(file, fs.createWriteStream(`uploads/${filename}`));

    return h.response({ filename }).code(201);
  },
});

output 三种模式:stream(流,大文件唯一正确选择)、data(整个 Buffer 进内存,仅限小文件)、file(直接落临时文件)。

文件校验体系

Hapi 配置层之外,业务校验在 handler 内组合:

const ALLOWED = ['image/jpeg', 'image/png'];

// MIME 类型(hapi 从请求头解析)
if (!ALLOWED.includes(file.hapi.headers['content-type'])) {
  return h.response({ message: '文件类型不支持' }).code(415);
}

完整校验链:content-type 头 → 扩展名白名单 → 文件头嗅探(magic bytes)。maxBytes 超限会收到 413 响应,错误处理在 onPreResponse 扩展点统一格式化。

多文件与附加字段

同一个 input 多选或多个文件字段:

handler: async (request, h) => {
  const { photos, caption } = request.payload;
  const files = Array.isArray(photos) ? photos : [photos];

  const saved = [];
  for (const file of files) {
    const filename = `${crypto.randomUUID()}-${path.basename(file.hapi.filename)}`;
    await pipeline(file, fs.createWriteStream(`uploads/${filename}`));
    saved.push(filename);
  }
  return h.response({ saved, caption }).code(201);
}

multipart 中的文本字段(caption)与文件字段在 payload 里共存,直接取用。

进度追踪

流式模式的福利:file.on('data') 累计字节数即可算进度百分比,配合 SSE 或 WebSocket 推给前端。超大文件场景建议直接改用分片上传协议(tus)或对象存储预签名直传,hapi 只接元数据回调。

跟踪上传失败发生的阶段

Hapi.js 文件上传完全指南需要把请求校验、文件接收、内容检查和对象存储写入区分开。向观测云上报脱敏的失败阶段、文件大小区间和耗时,结合已插桩的存储调用排查超时。不要把原始文件内容、上传令牌或个人文件名写入日志;监控用于定位故障,不代替文件类型验证、鉴权与恶意内容检测。

接入文档:日志采集 · Node.js APM 接入 · 监控器与告警策略。

常见问题(FAQ)

Q:Hapi 上传和 multer(Express 系)有什么本质区别?

理念差异:multer 是中间件(处理完挂到 req.file),Hapi 是框架内建 payload 语义(配置即行为)。功能等价,Hapi 的声明式配置在安全审计时更友好。

Q:413 Payload Too Large 的响应能自定义吗?

用 server.ext('onPreResponse', ...) 拦截 Boom 错误,改写为统一错误格式;同时在 payload 配置里设 failAction 控制超限行为。

Q:上传目录如何规划?

按日期/租户分目录(uploads/2026/10/),文件名 UUID 化;上传目录与应用代码分离挂载,Web 层不直接暴露——下载走鉴权接口或对象存储签名 URL。


参考文档

本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台