文件上传与设备摄像头采集:hackathon-starter 的 Multer 实战教程
2026/9/20 23:47:02 网站建设 项目流程

文件上传与设备摄像头采集:hackathon-starter 的 Multer 实战教程

【免费下载链接】hackathon-starterA boilerplate for Node.js web applications项目地址: https://gitcode.com/gh_mirrors/ha/hackathon-starter

在 Node.js 项目里实现文件上传,Multer 是最常用的中间件方案。hackathon-starter 作为一套完整的 Node.js Web 应用脚手架,内置了两个 Multer 实战案例:一个是经典的/api/upload磁盘文件上传,另一个是/ai/llm-camera设备摄像头采集图片并直接送给视觉大模型分析。本文带你读懂这两条完整链路,从表单、中间件到错误处理,一次学会 Multer 的两种典型用法。

为什么选 Multer 处理 Node.js 文件上传?

浏览器提交的文件表单使用multipart/form-data编码,Express 默认并不解析这种请求体。Multer 的工作就是把它解析出来,并把文件落到两个地方之一:

  • 磁盘存储multer({ dest: '...' }),文件写入指定目录,适合"存文件、给下载"的场景
  • 内存存储multer.memoryStorage(),文件内容以 Buffer 放在req.file.buffer,适合"上传后立即处理、不落盘"的场景

hackathon-starter 的两个案例恰好各用了一种,非常适合对照学习。依赖在 package.json 中声明,版本为multer ^2.4.0,README.md 也把它列为核心功能之一。

经典文件上传:1MB 限制的磁盘存储示例

打开/api/upload页面,你看到的是 views/api/upload.pug 定义的标准表单:

  • 表单声明enctype='multipart/form-data'(文件上传的必备属性)
  • 隐藏字段_csrf携带 CSRF 令牌,防跨站伪造
  • 文件输入框的字段名是myFile

真正干活的是 controllers/api.js 中的uploadMiddleware

const upload = multer({ dest: path.join(__dirname, '../uploads'), // 存到 uploads/ 目录 limits: { fileSize: 1024 * 1024 * 1 }, // 单文件上限 1MB }); upload.single('myFile')(req, res, (err) => { if (err) req.multerError = err; // 错误先挂到 req 上 next(); });

这里有个值得学习的设计:中间件不直接终止请求,而是把 Multer 的错误记录到req.multerError,交给后续处理器决定怎么提示用户。

上传失败提示与超大文件错误的优雅处理

postFileUpload(controllers/api.js)展示了完整的错误分支:

  1. 文件超过 1MB → Multer 抛出LIMIT_FILE_SIZE错误 → 页面显示"File size is too large"
  2. 其他 Multer 错误 → 透出原始错误信息
  3. 上传成功 → 绿色成功提示,并 302 重定向回上传页

每个分支都先调用req.session.save(...)再重定向。这是一个容易被忽略的细节:如果用 Redis 或 Mongo 等异步会话存储,不先保存会话,重定向后新请求读不到 flash 消息,提示就会"丢闪"。

这套行为的正确性由端到端测试覆盖,见 test/e2e-nokey/upload.e2e.test.js:小文件上传成功、内容一致;超过 1MB 报错提示;恰好接近 1MB 仍可上传;文本/JSON/CSV/XML 多种类型均可通过。

设备摄像头采集:Multer 内存存储的进阶玩法

第二个案例更有意思:/ai/llm-camera页面让浏览器调用设备摄像头拍照,把图片直接喂给视觉大模型分析。前端逻辑在 views/ai/llm-camera.pug:

  1. navigator.mediaDevices.enumerateDevices()枚举设备上的摄像头
  2. getUserMedia()获取视频流,在<video>上实时预览
  3. 点击"Capture"时用<canvas>抓取一帧,转成 JPEG Blob
  4. FormData把图片以字段名imagePOST 到/ai/llm-camera

后端则用 Multer 的内存存储接住图片(controllers/ai.js):

multer({ storage: multer.memoryStorage(), limits: { fileSize: 10 * 1024 * 1024 }, // 10MB 上限 }).single('image');

为什么用内存而不是磁盘?因为这张照片不需要保存——它马上会被转成 Base64 Data URL 送给 Groq 视觉模型(controllers/ai.js),落盘反而浪费 IO,还可能留下用户隐私数据。内存用完即弃,是这类"过路图片"的最佳实践。

中间件顺序与安全防护细节

在 app.js 和路由注册处,有两处值得注意的约定:

  • Multer 必须跑在 Lusca CSRF 校验之前/api/upload/ai/llm-camera两条路径在全局 CSRF 中间件里被放行,改由各自的 POST 路由末端再挂lusca({ csrf: true })单独校验,因为 multipart 请求体解析和 CSRF 校验的顺序容易冲突。
  • 限流保护:两个 POST 路由都挂了strictLimiter,防止上传接口被滥用。
  • 页面级路由(GET)统一通过lusca({ csrf: true })保护,表单里的_csrf隐藏字段与之配套。

这套"上传接口 + 限流 + CSRF"的组合拳,可以直接照搬到你自己的项目里。

关键文件速查清单

文件作用
controllers/api.js磁盘上传:页面、中间件、成功/失败处理
views/api/upload.pug上传表单(multipart + CSRF)
controllers/ai.js内存上传 + Base64 + 视觉分析
views/ai/llm-camera.pug摄像头枚举、预览、拍照前端逻辑
app.js路由注册与中间件顺序
test/e2e-nokey/upload.e2e.test.js上传功能的端到端测试

小结

通过 hackathon-starter 的两个案例,你可以把 Multer 的用法浓缩成三条经验:

  1. 要存盘就用dest,要现处理就用memoryStorage,按文件的生命周期选型
  2. limits.fileSize一定要设,并把LIMIT_FILE_SIZE等错误翻译成用户能看懂的提示
  3. 上传接口记得组合限流与 CSRF 防护,中间件顺序(Multer 在前、CSRF 校验在后)别搞反

照着 AGENTS.md 和 AGENTS.md 中的功能速查表,你可以快速定位这两个功能的完整上下文,动手改造出自己的上传能力。🚀

【免费下载链接】hackathon-starterA boilerplate for Node.js web applications项目地址: https://gitcode.com/gh_mirrors/ha/hackathon-starter

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询