Vapor 4+ 无内置 File 类型,文件上传需通过 HTTPPart 的 filename 判断是否为文件,并用 part.stream() 流式处理避免内存溢出,而非 part.data() 全量加载。

Swift Vapor 中 File 对象不存在,实际用的是 FileIO 和 HTTPPart
Vapor 4+ 没有名为 File 的内置类型——这是常见误解。上传文件时,请求体被解析为 multipart 数据,每个字段对应一个 HTTPPart;而文件内容的读写依赖 FileIO(异步 I/O 工具)或直接流式处理。若你在文档或旧代码里看到 File,大概率是自定义模型或 Vapor 2/3 的遗留命名。
如何从 HTTPPart 提取上传的文件名和内容
multipart 请求中,文件字段会带 Content-Disposition 头,其中包含 filename 参数。Vapor 自动解析它,但需手动检查是否为文件(而非普通表单字段):
app.post("upload") { req -> EventLoopFuture in
guard let part = req.http.body.part(named: "file") else {
return req.eventLoop.makeFailedFuture(Abort(.badRequest))
}
// 判断是否为文件:检查是否有 filename
guard let filename = part.filename else {
return req.eventLoop.makeFailedFuture(Abort(.badRequest, reason: "No filename provided"))
}
// 可选:校验文件类型(基于 Content-Type)
let contentType = part.contentType?.description ?? "application/octet-stream"
// 读取全部内容到内存(仅限小文件!)
return part.data()
.flatMap { data in
let outputPath = "/tmp/uploaded_\(filename)"
return req.fileio.writeFile(data, at: outputPath)
}
.map { _ in .ok }
}
-
part.filename是可选值,只有带filename=...的 part 才算文件上传 -
part.data()把整个文件加载进内存,不适用于大文件;生产环境应改用part.stream()+ 分块写入 -
req.fileio.writeFile(...)是异步写入,路径需确保目录存在且进程有写权限
大文件上传必须用 part.stream() 避免内存爆炸
上传 10MB+ 文件时,part.data() 会把全部字节载入 RAM,极易触发 OOM。正确做法是用 part.stream() 获取 AsyncThrowingStream,逐块写入磁盘或转发:
return part.stream()
.write(to: "/tmp/\(filename)", on: req.application.fileio)
.map { _ in .ok }
-
AsyncThrowingStream是 Swift 5.5+ 原生流类型,Vapor 封装了底层 byte buffer 流控 -
write(to:on:)是AsyncThrowingStream的扩展方法,自动处理分块、flush 和 close - 若需校验哈希或转存到 S3,应在 stream 的
forEach中处理每个ByteBuffer,而不是先 collect 全量
常见错误:part.filename 为 nil 却当成文件处理
最常踩的坑是没区分表单字段和文件字段。例如 HTML 写成 (无 type="file"),或漏了 enctype="multipart/form-data",此时 part.filename == nil,但开发者仍调用 part.data() —— 这会静默读取空内容,后续保存得到零字节文件。
- 永远先判
if let filename = part.filename,再做文件逻辑 -
前端必须用
,且文件 input 要有name与后端part(named: "...")一致 - Vapor 日志不会报错,但
part.contentType在非文件场景下通常为nil或text/plain,可辅助判断
文件上传不是“拿个 File 对象点保存”那么简单;核心在于理解 multipart 解析时机、流式边界控制,以及 filename 字段才是文件身份的唯一可信标识。










