如何使用Vapor 3处理多部分请求

Mar*_*tin 4 swift vapor

我是个蒸气初学者,我选择从Vapor 3-rc开始,因为它似乎破坏了Vaport 2的更改。不幸的是,目前没有完整的文档。

我目前正在尝试从Postman上传一个简单的txt文件到我的Vapor 3本地服务器。

这是我的路线

let uploadController = FileUploadController()
router.post("uploadtxt", use: uploadController.uploadTXT)
Run Code Online (Sandbox Code Playgroud)

和我的控制器

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"
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

首先,通过执行Postman请求,服务器将返回:

{"error":true,"reason":"There is no configured decoder for multipart\/form-data; boundary=...}
Run Code Online (Sandbox Code Playgroud)

通过调查源代码和有关此的有限文档,似乎我应该声明一个解码器来支持多部分传入的请求。

所以我做了:

var contentConfig = ContentConfig.default()
let decoder = FormURLDecoder()
contentConfig.use(decoder: decoder, for: .multipart)
services.register(contentConfig)
Run Code Online (Sandbox Code Playgroud)

FormURLDecoder之所以使用它,是因为它似乎是我所需要的最接近的类。BodyDecoder

现在infite-环插入func decode<T>(_ type: T.Type) throws -> T where T: DecodableFormURLSingleValueDecoder,而我用很少的网络资源被困在这里。

Mar*_*tin 5

我结束了Vapor松弛活动,这是查找一些信息和一些帮助的好地方。

解决方案非常简单。而不是使用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>
Run Code Online (Sandbox Code Playgroud)

我创建了这个小结构

fileprivate struct MyFile: Content {
    var filename: String
    var filedata: Data
}
Run Code Online (Sandbox Code Playgroud)

而且,在我的控制器中:

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
    })
}
Run Code Online (Sandbox Code Playgroud)