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

Posted

技术标签:

【中文标题】如何使用 Vapor 3 处理多部分请求【英文标题】:How to handle multipart request with Vapor 3 【发布时间】:2018-03-26 10:18:03 【问题描述】:

我是一个蒸汽初学者,我选择从 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 请求,服务器返回:

"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,因为它似乎是最符合我需要的 IMO 类,实现了BodyDecoder

现在它无限循环到 func decode&lt;T&gt;(_ type: T.Type) throws -&gt; T where T: DecodableFormURLSingleValueDecoder,我被困在这里,网络资源很少。

【问题讨论】:

【参考方案1】:

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

解决方法很简单。与其使用req.content.decode(MultipartForm.self),不如使用MultipartForm.decode(from: req)(...已删除代码示例)

编辑:

正如@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
    )

【讨论】:

在这些小控制器中发生了很多事情,我发现它们很难准确地理解每个 sn-p 正在完成的工作。我只是问了一个问题,然后阅读了您的帖子。我想也许我也需要使用 multipartform (但我不确定如何)? ***.com/questions/49594004/… 我刚看了你的帖子,你不需要多部分。 Multipart用于文件上传,您需要form-datax-www-urlencoded 已在 Vapor 3.0.0 rc 2.4 中修复。文档更新:docs.vapor.codes/3.0/multipart/overview 没有真正修复,因为 Multipart v 3.0.0 中不再存在 MultipartForm 0 感谢您更新您的答案@Martin! Vapor 团队非常喜欢“快速行动并打破常规”。没关系,如果它同时被记录在案,但 Tanner 使用了一些魔法来解码表格,我无法理解它。所有其他的博客、魔法书等也都过时了。当然,其中大多数已经更新。仍然很高兴这个互联网智慧的 sn-p 现在也是正确的! ?

以上是关于如何使用 Vapor 3 处理多部分请求的主要内容,如果未能解决你的问题,请参考以下文章

如何在Vapor 3中从JSON响应中保存父子关系

Swift Vapor 服务器:如何在获取请求中返回嵌套字典?

如何使用 vapor 3.x 构建蒸汽工具箱

Vapor:如何协调多个请求,直到完成一个中心请求

如何从 Vapor 3 中的 JSON 响应中保存父子关系

如何通过 Vapor 获取远程 IP