不使用 http2 连接调用 URLSessionDataDelegate
URLSessionDataDelegate not being called using http2 connection
更新
我发现如果我 运行 服务器,然后是 macOS 应用程序并保持 40 秒(因此服务器发送了 40 "a"
个字符,每秒一个)然后最终didReceive response
委托被调用,然后 didReceive data
委托开始被每个新数据位调用。这导致在 macOS 应用程序的控制台中记录如下:
URLAuthenticationChallenge
Got response: <NSHTTPURLResponse: 0x6080000385c0> { URL: https://localhost:10443/sub } { status code: 200, headers {
"Content-Type" = "text/plain; charset=utf-8";
Date = "Thu, 03 Nov 2016 16:51:28 GMT";
Vary = "Accept-Encoding";
} }
Received data: Optional("{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
...
这表明某处正在进行缓冲。
我一直在测试 URLSession
如何与 HTTP/2 连接一起工作,我 运行 遇到了一些问题。
我这里有一个非常简单的 macOS 应用程序:https://github.com/hamchapman/http2-barebones-mac-app 虽然它的整个代码基本上就是这样:
class ViewController: NSViewController, URLSessionDelegate, URLSessionDataDelegate {
override func viewDidLoad() {
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "localhost"
urlComponents.port = 10443
guard let url = urlComponents.url else {
print("Bad URL, try again")
return
}
var request = URLRequest(url: url.appendingPathComponent("/sub"))
request.httpMethod = "SUB"
request.timeoutInterval = REALLY_LONG_TIME
let sessionConfiguration = URLSessionConfiguration.ephemeral
sessionConfiguration.timeoutIntervalForResource = REALLY_LONG_TIME
sessionConfiguration.timeoutIntervalForRequest = REALLY_LONG_TIME
let session = Foundation.URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: nil)
let task: URLSessionDataTask = session.dataTask(with: request)
task.resume()
}
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
print("Got response: \(response)")
completionHandler(.allow)
}
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
let dataString = String(data: data, encoding: .utf8)
print("Received data: \(dataString)")
}
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print("Error: \(error)")
}
// So it works with self-signed certs (we don't care about TLS etc in this example)
public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.previousFailureCount == 0 else {
challenge.sender?.cancel(challenge)
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let allowAllCredential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(.useCredential, allowAllCredential)
}
}
您可以看到正在使用的 http 方法是 SUB
。如果您想订阅给定的资源,这被设计为您使用的一种方法,在我的简单示例中,该资源位于路径 /sub
。理论上,当服务器有新数据要发送时,这应该能够利用 HTTP/2 流将新数据发送到 macOS 应用程序的连接。
这是我一直用作服务器的非常基本的 (Go) 应用程序:https://github.com/hamchapman/http2-barebones-server(自述文件中有关于如何 运行 它的说明)。
它基本上设置为在 /sub
接受 SUB
请求并立即发回 200 OK,然后每秒发送 "a"
作为一点数据。
我面临的问题是,就 Go 服务器而言,连接正常。但是,URLSessionDelegate
被调用时使用了预期的 URLAuthenticationChallenge
(服务器只允许加密连接),但是 URLSessionDataDelegate
方法在接收到响应和接收到数据时被调用是永远不会叫。
您可以通过 运行 连接服务器然后使用以下 curl 命令来验证服务器是否按预期工作:
curl --http2 -k -v -X SUB https://localhost:10443/sub
(您可能需要下载最新版本的 curl - 请参阅此处了解信息:https://simonecarletti.com/blog/2016/01/http2-curl-macosx/)
我还验证了在 macOS 应用程序中建立的连接(使用 Wireshark)实际上正在接收数据,但从未调用委托。
有谁知道为什么会这样?数据是否在某处缓冲?在 URLSession
中 HTTP/2 支持不完全吗?
因为缓冲了前512个字节:https://forums.developer.apple.com/thread/64875
更新
我发现如果我 运行 服务器,然后是 macOS 应用程序并保持 40 秒(因此服务器发送了 40 "a"
个字符,每秒一个)然后最终didReceive response
委托被调用,然后 didReceive data
委托开始被每个新数据位调用。这导致在 macOS 应用程序的控制台中记录如下:
URLAuthenticationChallenge
Got response: <NSHTTPURLResponse: 0x6080000385c0> { URL: https://localhost:10443/sub } { status code: 200, headers {
"Content-Type" = "text/plain; charset=utf-8";
Date = "Thu, 03 Nov 2016 16:51:28 GMT";
Vary = "Accept-Encoding";
} }
Received data: Optional("{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
Received data: Optional("{\"Data\":\"a\"}\n")
...
这表明某处正在进行缓冲。
我一直在测试 URLSession
如何与 HTTP/2 连接一起工作,我 运行 遇到了一些问题。
我这里有一个非常简单的 macOS 应用程序:https://github.com/hamchapman/http2-barebones-mac-app 虽然它的整个代码基本上就是这样:
class ViewController: NSViewController, URLSessionDelegate, URLSessionDataDelegate {
override func viewDidLoad() {
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "localhost"
urlComponents.port = 10443
guard let url = urlComponents.url else {
print("Bad URL, try again")
return
}
var request = URLRequest(url: url.appendingPathComponent("/sub"))
request.httpMethod = "SUB"
request.timeoutInterval = REALLY_LONG_TIME
let sessionConfiguration = URLSessionConfiguration.ephemeral
sessionConfiguration.timeoutIntervalForResource = REALLY_LONG_TIME
sessionConfiguration.timeoutIntervalForRequest = REALLY_LONG_TIME
let session = Foundation.URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: nil)
let task: URLSessionDataTask = session.dataTask(with: request)
task.resume()
}
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
print("Got response: \(response)")
completionHandler(.allow)
}
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
let dataString = String(data: data, encoding: .utf8)
print("Received data: \(dataString)")
}
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print("Error: \(error)")
}
// So it works with self-signed certs (we don't care about TLS etc in this example)
public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.previousFailureCount == 0 else {
challenge.sender?.cancel(challenge)
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let allowAllCredential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(.useCredential, allowAllCredential)
}
}
您可以看到正在使用的 http 方法是 SUB
。如果您想订阅给定的资源,这被设计为您使用的一种方法,在我的简单示例中,该资源位于路径 /sub
。理论上,当服务器有新数据要发送时,这应该能够利用 HTTP/2 流将新数据发送到 macOS 应用程序的连接。
这是我一直用作服务器的非常基本的 (Go) 应用程序:https://github.com/hamchapman/http2-barebones-server(自述文件中有关于如何 运行 它的说明)。
它基本上设置为在 /sub
接受 SUB
请求并立即发回 200 OK,然后每秒发送 "a"
作为一点数据。
我面临的问题是,就 Go 服务器而言,连接正常。但是,URLSessionDelegate
被调用时使用了预期的 URLAuthenticationChallenge
(服务器只允许加密连接),但是 URLSessionDataDelegate
方法在接收到响应和接收到数据时被调用是永远不会叫。
您可以通过 运行 连接服务器然后使用以下 curl 命令来验证服务器是否按预期工作:
curl --http2 -k -v -X SUB https://localhost:10443/sub
(您可能需要下载最新版本的 curl - 请参阅此处了解信息:https://simonecarletti.com/blog/2016/01/http2-curl-macosx/)
我还验证了在 macOS 应用程序中建立的连接(使用 Wireshark)实际上正在接收数据,但从未调用委托。
有谁知道为什么会这样?数据是否在某处缓冲?在 URLSession
中 HTTP/2 支持不完全吗?
因为缓冲了前512个字节:https://forums.developer.apple.com/thread/64875