【发布时间】:2017-03-17 06:30:54
【问题描述】:
更新
我发现,如果我运行服务器,然后运行 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?
【问题讨论】:
-
你确定调用了completionHandler?
-
(我在
didReceive response委托函数中无意中删除了对completionHandler(.allow)的调用)。它从来没有被调用过,感觉就像问题的症结所在 -
在尝试将 NSURLSession 与
localhost一起使用时是否存在已知问题? -
我不知道,但这似乎完全有可能 - 有链接吗?
-
我添加了关于我现在看到的内容的更新。似乎
localhost不是问题,但正在进行某种缓冲。
标签: swift nsurlsession http2 nsurlsessiondatatask