【问题标题】:Vapor 3 - send a HTTPRequestVapor 3 - 发送一个 HTTPRequest
【发布时间】:2019-08-10 05:47:20
【问题描述】:

如何在 Vapor 3 中使用 HTTPRequest 结构发送 API 请求?

我尝试了以下代码的变体..

var headers: HTTPHeaders = .init()
let body = HTTPBody(string: a)            
let httpReq = HTTPRequest(
    method: .POST,
    url: URL(string: "/post")!,
    headers: headers,
    body: body)

let httpRes: EventLoopFuture<HTTPResponse> = HTTPClient.connect(hostname: "httpbin.org", on: req).map(to: HTTPResponse.self) { client in
    return client.send(httpReq)
}

编译错误Cannot convert value of type '(HTTPClient) -&gt; EventLoopFuture&lt;HTTPResponse&gt;' to expected argument type '(HTTPClient) -&gt; _'

我已经尝试过其他有效的代码变体。

Vapor 3 Beta Example Endpoint Request

let client = try req.make(Client.self)

let response: Future<Response> = client.get("http://example.vapor.codes/json")

我反复阅读:

【问题讨论】:

  • 我已经尝试过其他有效的代码变体 - 所以你得到了它的工作方式,但想改用HTTPRequest
  • 嘿@LinusGeffarth。我通过使用名为Client 的更高级别的包装器找到了一种更简单的方法。我发现 Protocol 的 cmets 在 Client.swift 的代码文件中非常有用。
  • 对于我未来的自己(和其他任何人):你需要做req.client().post(....),请参阅Client.swift 中的文档,就像上面描述的 rustyMagnet。

标签: vapor server-side-swift


【解决方案1】:

HTTPClient.connect 返回Future&lt;HTTPClient&gt;,它映射到Future&lt;HTTPResponse&gt; 而不是EventLoopFuture&lt;HTTPResponse&gt;

如果您期望单个 HTTPResponse 使用 HttpClient.send 而不是 HTTPClient.connect

如果您希望有多个 HTTPResponses,则必须更改 .map(to: HTTPResponse.self) 以正确映射到 EventLoopFuture&lt;HTTPResponse&gt;

【讨论】:

    【解决方案2】:

    您的问题是.map(to: HTTPResponse.self)。 Map 需要定期将其结果转换为新结果,就像您将 map 数组一样。但是,地图关闭的结果会返回 EventLoopFuture&lt;HTTPResponse&gt;。这会导致您的 map 函数返回 EventLoopFuture&lt;EventLoopFuture&lt;HTTPResponse&gt;&gt;

    为避免这种复杂性,请使用flatMap

    var headers: HTTPHeaders = .init()
    let body = HTTPBody(string: a)            
    let httpReq = HTTPRequest(
        method: .POST,
        url: URL(string: "/post")!,
        headers: headers,
        body: body)
    
    let client = HTTPClient.connect(hostname: "httpbin.org", on: req)
    
    let httpRes = client.flatMap(to: HTTPResponse.self) { client in
        return client.send(httpReq)
    }
    

    编辑: 如果您想使用 Content API,您可以这样做:

    let data = httpRes.flatMap(to: ExampleData.self) { httpResponse in
        let response = Response(http: httpResponse, using: req)
        return try response.content.decode(ExampleData.self)
    }
    

    【讨论】:

    • 真的很好@JoannisO。如何访问响应的实际内容并将Future&lt;Response&gt; 转换为Future&lt;ExampleData&gt;?参考您在stackoverflow.com/questions/48589415/… 中的回答?我似乎无法使用该样式访问response.content.decode
    • 没错,因为您使用的是更多低级 API。 HTTPResponse 是响应的原始表示。 Vapor“内容”API 是高级 API。因此,您需要使用高级 Vapor 客户端 API 来访问这些功能。但是,如果您坚持使用较低级别的 HTTPClient,则可以这样做。在帖子中查看我的更新。
    • 谢谢@JoannisO。完美运行。我注意到您将Worker 设置为app。那是一个错误吗?还是我误用了req
    • @rustyMagnet 是的,这是我的错误。我在main.swift 中对此进行了测试,您可以在其中以与容器相同的方式使用应用程序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多