美文网首页
Vapor文档学习廿九: HTTP -Body

Vapor文档学习廿九: HTTP -Body

作者: Supremodeamor | 来源:发表于2017-04-24 15:31 被阅读75次

    HTTP.Body承载着HTTP.Message,用于底层数据的传输。这些数据可能是Json,html,文本或者图片。

    public enum Body {
        case data(Bytes)
        case chunked((ChunkStream) throws -> Void)
    }
    

    Data Case

    dataHTTP.Messagebody最常用的,它是简单的字节数组,一系列与之相关的类型或协议都定义在headerContent-Type中。下面来看一些🌰。

    Application/JSON

    如果我们的Content-Type中包含application/json,那表明底层数据是序列化的JSON数据。

    if let contentType = req.headers["Content-Type"], contentType.contains("application/json"), let bytes = req.body.bytes {
      let json = try JSON(bytes: bytes)
      print("Got JSON: \(json)")
    }
    

    Image/PNG

    如果我们的Content-Type中包含image/png,那表明底层数据时编码的png图片

    if let contentType = req.headers["Content-Type"], contentType.contains("image/png"), let bytes = req.body.bytes {
      try database.save(image: bytes)
    }
    

    Chunked Case

    在vapor中chunked仅使用与外部HTTP.Message,传统的response角色是收集整个body然后将其传递。我们可以利用代码块异步发送body。

    let body: Body = Body.chunked(sender)
    return Response(status: .ok, body: body)
    

    我们可以手动实现,或者使用Vapor内置的初始方法快捷创建代码块body。

    return Response(status: .ok) { chunker in
      for name in ["joe", "pam", "cheryl"] {
          sleep(1)
          try chunker.send(name)
      }
    
      try chunker.close()
    }
    

    Note: 注意在chunker销毁之前调用close()。

    BodyRepresentable

    除了常见的Body具体类型,Vapor还广泛的支持BodyRepresentable,这意味着对象可以转换为Body类型互换使用。比如:

    return Response(body: "Hello, World!")
    

    上例中字符串会转换为字节添加到body中。

    实际我们最好使用return "Hello, World!",Vapor会自动为Content-Type设置适当的值。

    看一下这是如何实现的:

    public protocol BodyRepresentable {
        func makeBody() -> Body
    }
    

    Custom

    我们可以将自定义的类型遵守HTTP.BodyRepresentable协议。如下例子中假设我们有一个.vpr文件,可转换为VPRFilemodel,就可以作为body使用。

    extension VPRFile: HTTP.BodyRepresentable {
      func makeBody() -> Body {
        // collect bytes
        return .data(bytes)
      }
    }
    

    你可能注意到了协议中是包含“thows”的,但是我们的实现中没有,这在swift中是完全可以的。这样你在手动调用该方法时就不用再抛出异常了。

    然后我们就可以直接在Response中使用VRP文件了。

    drop.get("files", ":file-name") { request in
      let filename = try request.parameters.extract("file-name") as String
      let file = VPRFileManager.fetch(filename)
      return Response(status: .ok, headers: ["Content-Type": "file/vpr"], body: file)
    }
    

    实际上,如果我们经常重复这个操作,我们可能会将VPRFile直接与ResponseRepresentable配合使用:

    extension VPRFile: HTTP.ResponseRepresentable {
      func makeResponse() -> Response {
        return Response(
          status: .ok,
          headers: ["Content-Type": "file/vpr"],
          body: file
        )
      }
    }
    

    上面的例子也会改成这样:

    drop.get("files", ":file-name") { request in
      let filename = try request.parameters.extract("file-name") as String
      return VPRFileManager.fetch(filename)
    }
    

    我们也可以使用类型安全的路由使其更简洁:

    drop.get("files", String.self) { request, filename in
      return VPRFileManager.fetch(filename)
    }
    

    相关文章

      网友评论

          本文标题:Vapor文档学习廿九: HTTP -Body

          本文链接:https://www.haomeiwen.com/subject/jslpzttx.html