Swift 合并 HTTP 请求
Swift Combine HTTP request
正在尝试了解如何使用 combine 快速发出 http 请求。我主要看的是 Apple 的这个 doc。虽然我没有取得任何进展,但它看起来很简单,所以我不知道我做错了什么。
我习惯 JavaScript 并使用 Fetch API
在 Golang
中也使用 to http pkg
但出于某种原因,在 Swift 中做这件事真的让我感到困惑,因为它不像我提到的两个那样非常精简
我正在使用 SwiftUI 和 MVVM 架构,所以我的目标是在我的视图模型中实现一种与我的 Golang 服务器通信的方式。
这主要需要 POST
请求 Accept
和 Authorization
headers 以及 JSON
body
我试过这段代码:
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: \([=11=]).") },
receiveValue: { data in print ("Received user: \(data).")}
)
并获得此控制台消息:nw_protocol_get_quic_image_block_invoke dlopen libquic failed
我读到的 here 可能与我的问题无关,但我认为他们在谈论 firebase。
我想知道我的代码有没有问题?
或者一些 JSON
API 的工作示例,甚至是某些网站的 http GET
请求都可以。
谢谢!
让我们对您的代码做一个非常基本的缩减:
let request = URLRequest(url: URL(string:"https://www.apple.com")!)
_ = URLSession.shared.dataTaskPublisher(for: request)
.sink(receiveCompletion: {_ in print("completion")},
receiveValue: { print([=10=]) })
结果:根本不打印任何内容。
好的,现在让我们按照我在评论中的建议进行操作。我们有一个实例 属性:
var storage = Set<AnyCancellable>()
然后我们将代码更改为如下所示:
URLSession.shared.dataTaskPublisher(for: request)
.sink(receiveCompletion: {_ in print("completion")},
receiveValue: { print([=12=]) })
.store(in:&self.storage)
我们在控制台中得到了这个(好吧,至少我是这样的):
(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
要理解其中的区别,或许想想赫拉克利特会有所帮助。 “你不能两次踏入同一条河流,因为不同的水域一直在流动。”那条河是时间.
在你的代码中,发布者到接收器的管道被创建并被丢弃——因为它是纯粹是这个方法的本地方法,它创建管道并立即结束。与此同时,河流在流动!因此,在请求甚至有机会开始之前,管道就已经消失了。它永远不会开始,所以它永远不会结束。它永远不会完成,所以它永远不会打印。
在 my 代码中,发布者到接收器的管道是 preserved(例如 属性).这就是 store
所做的。因此请求有机会开始,并且在管道创建很久之后它有机会完成,而河流一直在流动。
希望可以帮助到某人:
我确实粘贴错误了:
@State var cancellableUploadTask: AnyCancellable?
而不是:
private var cancellableUploadTask: AnyCancellable?
失败了...
正在尝试了解如何使用 combine 快速发出 http 请求。我主要看的是 Apple 的这个 doc。虽然我没有取得任何进展,但它看起来很简单,所以我不知道我做错了什么。
我习惯 JavaScript 并使用 Fetch API
在 Golang
中也使用 to http pkg
但出于某种原因,在 Swift 中做这件事真的让我感到困惑,因为它不像我提到的两个那样非常精简
我正在使用 SwiftUI 和 MVVM 架构,所以我的目标是在我的视图模型中实现一种与我的 Golang 服务器通信的方式。
这主要需要 POST
请求 Accept
和 Authorization
headers 以及 JSON
body
我试过这段代码:
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: \([=11=]).") },
receiveValue: { data in print ("Received user: \(data).")}
)
并获得此控制台消息:nw_protocol_get_quic_image_block_invoke dlopen libquic failed
我读到的 here 可能与我的问题无关,但我认为他们在谈论 firebase。
我想知道我的代码有没有问题?
或者一些 JSON
API 的工作示例,甚至是某些网站的 http GET
请求都可以。
谢谢!
让我们对您的代码做一个非常基本的缩减:
let request = URLRequest(url: URL(string:"https://www.apple.com")!)
_ = URLSession.shared.dataTaskPublisher(for: request)
.sink(receiveCompletion: {_ in print("completion")},
receiveValue: { print([=10=]) })
结果:根本不打印任何内容。
好的,现在让我们按照我在评论中的建议进行操作。我们有一个实例 属性:
var storage = Set<AnyCancellable>()
然后我们将代码更改为如下所示:
URLSession.shared.dataTaskPublisher(for: request)
.sink(receiveCompletion: {_ in print("completion")},
receiveValue: { print([=12=]) })
.store(in:&self.storage)
我们在控制台中得到了这个(好吧,至少我是这样的):
(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
要理解其中的区别,或许想想赫拉克利特会有所帮助。 “你不能两次踏入同一条河流,因为不同的水域一直在流动。”那条河是时间.
在你的代码中,发布者到接收器的管道被创建并被丢弃——因为它是纯粹是这个方法的本地方法,它创建管道并立即结束。与此同时,河流在流动!因此,在请求甚至有机会开始之前,管道就已经消失了。它永远不会开始,所以它永远不会结束。它永远不会完成,所以它永远不会打印。
在 my 代码中,发布者到接收器的管道是 preserved(例如 属性).这就是
store
所做的。因此请求有机会开始,并且在管道创建很久之后它有机会完成,而河流一直在流动。
希望可以帮助到某人:
我确实粘贴错误了:
@State var cancellableUploadTask: AnyCancellable?
而不是:
private var cancellableUploadTask: AnyCancellable?
失败了...