表单与文件上传
Hono 可以通过 Web 标准的 formData() 读取表单字段和上传文件。不同运行时对文件大小、临时存储和流式处理能力可能不同,生产环境要结合平台限制设计。
读取普通表单
app.post('/contact', async (c) => {
const form = await c.req.formData()
const email = String(form.get('email') ?? '')
const message = String(form.get('message') ?? '')
if (!email || !message) {
return c.json({ message: 'email and message are required' }, 400)
}
return c.json({
received: true,
email,
})
})
HTML 表单:
<form action="/contact" method="post">
<input name="email" type="email" />
<textarea name="message"></textarea>
<button type="submit">提交</button>
</form>
读取文件
app.post('/upload', async (c) => {
const form = await c.req.formData()
const file = form.get('file')
if (!(file instanceof File)) {
return c.json({ message: 'file is required' }, 400)
}
return c.json({
name: file.name,
type: file.type,
size: file.size,
})
})
测试:
curl -X POST http://localhost:3000/upload \
-F "file=@./avatar.png"
保存文件
Node.js 中可以把文件转换为 ArrayBuffer 后写入磁盘:
import { writeFile } from 'node:fs/promises'
import { join } from 'node:path'
app.post('/upload', async (c) => {
const form = await c.req.formData()
const file = form.get('file')
if (!(file instanceof File)) {
return c.json({ message: 'file is required' }, 400)
}
const bytes = await file.arrayBuffer()
const filename = `${crypto.randomUUID()}-${file.name}`
const path = join(process.cwd(), 'uploads', filename)
await writeFile(path, Buffer.from(bytes))
return c.json({ filename })
})
Cloudflare Workers 中更常见的是写入 R2,而不是本地文件系统。
安全注意事项
- 限制上传大小,避免内存被大文件耗尽。
- 不要信任客户端传来的文件名。
- 检查 MIME 类型和文件内容,特别是图片、压缩包和可执行文件。
- 私有文件不要直接放在公开静态目录。
- 对上传结果做鉴权,避免任意用户读取其他用户文件。
如果文件上传是核心功能,建议使用对象存储,并将上传、扫描、缩略图、访问控制拆成清晰流程。
相关内容
- Hono 是什么 介绍 Hono 的定位、核心特点、Web Standards 思路、多运行时能力,以及它与传统 Node.js Web 框架的差异。
- 安装和 Hello World 学习使用 create-hono 创建 Hono 项目,分别了解通用模板和 Node.js 模板的 Hello World 写法。
- 运行时选择 对比 Hono 在 Node.js、Cloudflare Workers、Bun、Deno 等运行时中的入口写法、部署方式和适用场景。
- 路由基础 学习 Hono 的 GET、POST、动态参数、通配符、路由分组和模块化路由写法。
- Context 详解 介绍 Hono Context 的 req、json、text、html、redirect、header、status、set、get 等常用 API。
- 中间件机制 学习 Hono 中间件的执行顺序、自定义中间件写法、路径匹配、next 调用和常见使用场景。