有人有在iOS上打开HTTP流的经验吗?我已经尝试了多种解决方案,但没有任何运气(下面的例子)。
为了更好的上下文,下面是在打开连接时将流值(作为ndjson)的端点的示例:
GET /v2/path/{id}
Accept: application/x-ndjson
尝试#1:
问题:从未调用完成处理程序
let keyID = try keyAdapter.getKeyID(for: .signHash)
let url = baseURL.appendingPathComponent("/v2/path/\(keyID)")
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "GET"
urlRequest.setValue("application/x-ndjson", forHTTPHeaderField: "Accept")
session.dataTask(with: urlRequest) { data, response, error in
// This never gets called.
// I would expect that the completion is called every time backend emits new value.
}.resume()
尝试#2:
问题:调试器显示以下消息:Connection 0: encountered error(12:1)
private var stream: URLSessionStreamTask? = nil
func startStream() {
let keyID = try keyAdapter.getKeyID(for: .signHash)
let url = baseURL.appendingPathComponent("/v2/path/\(keyID)")
let stream = session.streamTask(withHostName: url, port: 443)
// Not sure how to set headers.
// Header needs to be set so backend knows client wants to connect a stream.
self.stream = stream
stream.startSecureConnection()
startRead(stream: stream)
}
private func startRead(stream: URLSessionStreamTask) {
stream.readData(ofMinLength: 1, maxLength: 4096, timeout: 120.0) { data, endOfFile, error in
if let error = error {
Logger.shared.log(level: .error, "Reading data from stream failed with error: \(error.localizedDescription)")
} else if let data = data {
Logger.shared.log(level: .error, "Received data from stream (\(data.count)B)")
if !endOfFile {
self.startRead(stream: stream)
} else {
Logger.shared.log(level: .info, "End of file")
}
} else {
Logger.shared.log(level: .error, "Reading stream endup in unspecified state (both data and error are nil).")
}
}
}
有人有这方面的经验吗?我如何保持HTTP连接打开,并听取后端正在流的新值?
2条答案
按热度按时间iezvtpos1#
iOS可以使用现在已弃用的API
URLConnection
连接到HTTP流。该API在iOS 9中已弃用,但仍然可以使用(并将在iOS 16中测试)。首先,你需要创建
URLRequest
并设置NSURLConnection
:注意,上面代码中delegate的参数是
Any
类型,这对确定要实现什么协议没有帮助,有两个参数-NSURLConnectionDelegate
和NSURLConnectionDataDelegate
。让我们接收数据:
然后实现一个捕获错误的方法:
如果您有自定义SSL固定,则:
互联网上没有太多的信息,所以希望它能保存一些人几天的试错。
dsf9zpds2#
我今天也在寻找同样的解决方案,一开始我尝试使用
session.streamTask
,但我不知道如何使用它,这是TCP的低级任务,但我想要的是HTTP级别的解决方案。我也不想使用URLConnection
,它已经被弃用了。经过一番研究,我终于弄明白了:在
URLSessionDataDelegate
、https://developer.apple.com/documentation/foundation/urlsessiondatadelegate的文档中URLSession对象不需要有委托。如果没有分配委托,当你在该会话中创建任务时,你必须提供一个完成处理程序块来获取数据。
完成处理程序块主要是作为使用自定义委托的替代方案。如果您使用接受完成处理程序块的方法创建任务,则不会调用用于响应和数据传递的委托方法。
关键是不要在
dataTask()
中设置完成处理程序块,并实现URLSessionDataDelegate
的2个委托方法:另一个关键是将委托设置为
URLSessionDataTask
,而不是URLSession
。Larme代码的问题是他将委托设置为URLSession
,因此不会调用函数urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive: Data)
。完整代码演示: