如何使用 Vapor 3 处理多部分请求
How to handle multipart request with Vapor 3
我是一名 Vapor 初学者,我选择从 Vapor 3-rc 开始,因为它似乎打破了 Vaport 2 的变化。不幸的是,目前还没有完整的文档。
我目前正在尝试将一个简单的 txt 文件从 Postman 上传到我的 Vapor 3 本地服务器。
这是我的路线
let uploadController = FileUploadController()
router.post("uploadtxt", use: uploadController.uploadTXT)
和我的控制器
final class FileUploadController {
func uploadTXT(_ req: Request) throws -> Future<String> {
return try req.content.decode(MultipartForm.self).map(to: String.self, { form in
let file = try form.getFile(named: "txtfile")
return file.filename ?? "no-file"
})
}
}
首先,通过执行Postman请求,服务器returns:
{"error":true,"reason":"There is no configured decoder for multipart\/form-data; boundary=...}
通过调查源代码和limited documentation,看来我应该声明一个解码器来支持多部分传入请求。
所以我做到了:
var contentConfig = ContentConfig.default()
let decoder = FormURLDecoder()
contentConfig.use(decoder: decoder, for: .multipart)
services.register(contentConfig)
我使用 FormURLDecoder
因为它似乎是最接近我的需求的 class IMO,实施 BodyDecoder
现在它无限循环到 FormURLSingleValueDecoder
的 func decode<T>(_ type: T.Type) throws -> T where T: Decodable
,我被困在这里,只有很少的网络资源。
我在 Vapor slack 上结束了,这是查找一些信息和一些帮助的好地方。
解决方法很简单。与其使用 req.content.decode(MultipartForm.self)
,不如使用 MultipartForm.decode(from: req)
(...删除的代码示例)
编辑:
AS @axello 说,MultipartForm
不存在了。我现在正在使用 req.content.decode(...)
方法来解析多部分数据。这个想法是创建一个对象来反映您的 HTML 表单输入。 Codable 会神奇地将数据映射到对象中。
例如,使用这种形式:
<form method="POST" action="upload" enctype="multipart/form-data" class="inputForm">
<input type="name" name="filename">
<input type="file" name="filedata">
<input type="submit" name="GO" value="Send" class="send">
</form>
我创建了这个小结构
fileprivate struct MyFile: Content {
var filename: String
var filedata: Data
}
并且,在我的控制器中:
func uploadTXT(_ req: Request) throws -> Future<String> {
return try req.content.decode(MyFile.self).map(to: String.self, { myFile in
let filename = myFile.filename // this is the first input
// ... and the second one:
guard let fileContent = String(data: myFile.filedata, encoding: .utf8) else {
throw Abort(.badRequest, reason: "Unreadable CSV file")
}
print(fileContent)
return filename
})
}
我是一名 Vapor 初学者,我选择从 Vapor 3-rc 开始,因为它似乎打破了 Vaport 2 的变化。不幸的是,目前还没有完整的文档。
我目前正在尝试将一个简单的 txt 文件从 Postman 上传到我的 Vapor 3 本地服务器。
这是我的路线
let uploadController = FileUploadController()
router.post("uploadtxt", use: uploadController.uploadTXT)
和我的控制器
final class FileUploadController {
func uploadTXT(_ req: Request) throws -> Future<String> {
return try req.content.decode(MultipartForm.self).map(to: String.self, { form in
let file = try form.getFile(named: "txtfile")
return file.filename ?? "no-file"
})
}
}
首先,通过执行Postman请求,服务器returns:
{"error":true,"reason":"There is no configured decoder for multipart\/form-data; boundary=...}
通过调查源代码和limited documentation,看来我应该声明一个解码器来支持多部分传入请求。
所以我做到了:
var contentConfig = ContentConfig.default()
let decoder = FormURLDecoder()
contentConfig.use(decoder: decoder, for: .multipart)
services.register(contentConfig)
我使用 FormURLDecoder
因为它似乎是最接近我的需求的 class IMO,实施 BodyDecoder
现在它无限循环到 FormURLSingleValueDecoder
的 func decode<T>(_ type: T.Type) throws -> T where T: Decodable
,我被困在这里,只有很少的网络资源。
我在 Vapor slack 上结束了,这是查找一些信息和一些帮助的好地方。
解决方法很简单。与其使用 req.content.decode(MultipartForm.self)
,不如使用 MultipartForm.decode(from: req)
(...删除的代码示例)
编辑:
AS @axello 说,MultipartForm
不存在了。我现在正在使用 req.content.decode(...)
方法来解析多部分数据。这个想法是创建一个对象来反映您的 HTML 表单输入。 Codable 会神奇地将数据映射到对象中。
例如,使用这种形式:
<form method="POST" action="upload" enctype="multipart/form-data" class="inputForm">
<input type="name" name="filename">
<input type="file" name="filedata">
<input type="submit" name="GO" value="Send" class="send">
</form>
我创建了这个小结构
fileprivate struct MyFile: Content {
var filename: String
var filedata: Data
}
并且,在我的控制器中:
func uploadTXT(_ req: Request) throws -> Future<String> {
return try req.content.decode(MyFile.self).map(to: String.self, { myFile in
let filename = myFile.filename // this is the first input
// ... and the second one:
guard let fileContent = String(data: myFile.filedata, encoding: .utf8) else {
throw Abort(.badRequest, reason: "Unreadable CSV file")
}
print(fileContent)
return filename
})
}