Swift 合并 HTTP 请求

Rya*_*Sam 0 http ios swift combine

试图弄清楚如何使用组合快速发出 http 请求。我主要是在看Apple 的这个文档。我没有取得任何进展,而且看起来很简单,所以我不知道我做错了什么。

我习惯使用 JavaScript 并使用Fetch API
也使用Golang 中的http pkg
但出于某种原因,在 Swift 中这样做对我来说真的很困惑,因为它不像我提到的两个那样精简

我将 SwiftUI 与 MVVM 架构一起使用,所以我的目标是在我的视图模型中实现一种与 Golang 服务器通信的方式。

这就要求大多POST与请求AcceptAuthorization头部和JSON身体

我试过这个代码:

let url = URL(string: "https://api.example.com/user/login")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue(String(format: "Bearer %s", idToken!), forHTTPHeaderField: "Authorization")
        
_ = URLSession.shared.dataTaskPublisher(for: request)
    .tryMap() { element -> Data in
        // not worried about the status code just trying to get any response.
        guard let httpResponse = element.response as? HTTPURLResponse, httpResponse.statusCode >= 200
        else {
            throw URLError(.badServerResponse)
        }
        return element.data
    }
    // .decode(type: LoginResponseData.self, decoder: JSONDecoder()) commenting this out because I just want to see any data.
    .sink(
        receiveCompletion: { print ("Received completion: \($0).") },
        receiveValue: { data in print ("Received user: \(data).")}
    )
Run Code Online (Sandbox Code Playgroud)

并收到此控制台消息:nw_protocol_get_quic_image_block_invoke dlopen libquic failed
在此处阅读的内容可能与我的问题无关,但是我认为他们在谈论 firebase。

我想知道我的代码是否有问题?
或者一个带有一些JSONAPI的工作示例,甚至是GET某个网站的 http请求都可以。

谢谢!

mat*_*att 9

让我们对您的代码进行非常基本的缩减:

    let request = URLRequest(url: URL(string:"https://www.apple.com")!)
    _ = URLSession.shared.dataTaskPublisher(for: request)
        .sink(receiveCompletion: {_ in print("completion")},
              receiveValue: { print($0) })
Run Code Online (Sandbox Code Playgroud)

结果:根本没有打印任何内容


好的,现在让我们按照我在评论中的建议进行操作。我们有一个实例属性:

var storage = Set<AnyCancellable>()
Run Code Online (Sandbox Code Playgroud)

我们将代码更改为如下所示:

    URLSession.shared.dataTaskPublisher(for: request)
        .sink(receiveCompletion: {_ in print("completion")},
              receiveValue: { print($0) })
        .store(in:&self.storage)
Run Code Online (Sandbox Code Playgroud)

我们在控制台中得到了这个(好吧,至少我是这样做的):

(data: 74909 bytes, response: <NSHTTPURLResponse: 0x600002e479e0> { URL: https://www.apple.com/ } { Status Code: 200, Headers {
    "Cache-Control" =     (
        "max-age=151"
    );
    "Content-Encoding" =     (
        gzip
    );
    "Content-Length" =     (
        10974
    );
    "Content-Type" =     (
        "text/html; charset=UTF-8"
    );
    Date =     (
        "Fri, 04 Dec 2020 17:45:50 GMT"
    );
    Expires =     (
        "Fri, 04 Dec 2020 17:48:21 GMT"
    );
    Server =     (
        Apache
    );
    "Set-Cookie" =     (
        "geo=US; path=/; domain=.apple.com",
        "ccl=uQisGvuhtgEjEZERqJarcpJqZcmsz2JEaxjveIr8V14=; path=/; domain=.apple.com"
    );
    "Strict-Transport-Security" =     (
        "max-age=31536000; includeSubDomains"
    );
    Vary =     (
        "Accept-Encoding"
    );
    "x-content-type-options" =     (
        nosniff
    );
    "x-frame-options" =     (
        SAMEORIGIN
    );
    "x-xss-protection" =     (
        "1; mode=block"
    );
} })
completion
Run Code Online (Sandbox Code Playgroud)

要了解这种差异,或许可以考虑一下赫拉克利特 (Heraclitus)。“你不能两次踏入同一条河流,因为不同的、不同的水源源不断地流动。” 那条河是时候了

  • 您的代码中,发布者到接收器的管道被创建并丢弃——因为它纯粹是这个方法的本地,它创建管道并立即结束。与此同时,河流正在流动!因此,在请求甚至有机会开始之前,管道就消失了。它永远不会开始,所以永远不会结束。它永远不会完成,所以它永远不会打印。

  • 我的代码中,发布者到接收器的管道被保留(在一个实例属性中)。这就是store它的作用。因此,请求有机会开始,并且在管道创建很久之后它还有机会结束,而河流则一直在流淌。