通过 Swift 访问 HTTPS URL 时出现错误 -9807
Error -9807 when accessing HTTPS URLs via Swift
我正在尝试使用 Swift 的 NSURLRequest
和 NSURLConnection
与 Riot Games(英雄联盟)API 进行通信。我似乎不仅遇到 Riot URL 问题,而且遇到所有 HTTPS URL 问题。
我在 Swift 游乐场中有以下代码:
func doGET(url: String) {
if let urlhandle = NSURL(string: url) {
var request = NSURLRequest(URL: urlhandle)
var response: NSURLResponse?
var error: NSErrorPointer = nil
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error)
println("\n\(url)\n")
println("\(response)\n\n")
} else {
println("Bad URL: \(url)")
}
}
doGET("http://google.com")
doGET("https://na.api.pvp.net/api/lol/na/v1.2/champion/1?api_key=\(apikey)")
doGET("https://google.com")
我得到以下 errors/output:
http://google.com
Optional(<NSHTTPURLResponse: 0x7fcff2443d60> { URL: http://www.google.com/ } { status code: 200, headers {
"Accept-Ranges" = none;
"Alternate-Protocol" = "80:quic,p=0.08";
"Cache-Control" = "private, max-age=0";
"Content-Type" = "text/html; charset=ISO-8859-1";
Date = "Wed, 25 Feb 2015 23:13:45 GMT";
Expires = "-1";
Server = gws;
"Transfer-Encoding" = Identity;
Vary = "Accept-Encoding";
"X-Frame-Options" = SAMEORIGIN;
"X-XSS-Protection" = "1; mode=block";
} })
2015-02-25 16:13:45.357 URL Requests[36397:3779864] NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9807)
https://na.api.pvp.net/api/lol/na/v1.2/champion/1?api_key=<redacted>
nil
2015-02-25 16:13:45.402 URL Requests[36397:3779864] NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9807)
https://google.com
nil
如您所见,请求在 HTTP URL 上成功,但在安全 HTTPS URL 上失败。如何允许使用 HTTPS?
它可能无法解决 https 问题,但在将链接转换为 NSURL 之前,您应该始终使用 stringByAddingPercentEscapesUsingEncoding
"http://google.com".stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
"https://na.api.pvp.net/api/lol/na/v1.2/champion/1?api_key=any key".stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! // "https://na.api.pvp.net/api/lol/na/v1.2/champion/1?api_key=any%20key"
func doGET(link: String) {
if let url = NSURL(string: link.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!) {
var response: NSURLResponse?
var error: NSErrorPointer = nil
let data = NSURLConnection.sendSynchronousRequest(NSURLRequest(URL: url), returningResponse: &response, error: error)
println("\n\(url)\n")
println("\(response)\n\n")
} else {
println("Bad URL")
}
}
您的代码应该可以在 'normal' 环境中运行。但是正如您提到的那样,您在大学里,接受服务器证书时可能存在问题。所以我会建议你添加 NSURLConnectionDelegate
并添加以下两个方法。我从戈登的回答中得到了这个想法 here。
func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace) -> Bool {
return protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
}
func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge) {
challenge.sender.useCredential(NSURLCredential(forTrust: challenge.protectionSpace.serverTrust), forAuthenticationChallenge: challenge)
}
问题中的情况是另一种情况,但我认为您的服务器证书也有同样的问题。
感谢@Christian 和@Leonardo。这似乎是我自己机器上的 firewall/certificate 问题。现有代码在命令提示符 (swift /path/to/file
) 中运行完美,仅在 Xcode 中失败。我希望它最终能在 Xcode 中运行,但当我到达它时我会跨过那座桥。
我正在尝试使用 Swift 的 NSURLRequest
和 NSURLConnection
与 Riot Games(英雄联盟)API 进行通信。我似乎不仅遇到 Riot URL 问题,而且遇到所有 HTTPS URL 问题。
我在 Swift 游乐场中有以下代码:
func doGET(url: String) {
if let urlhandle = NSURL(string: url) {
var request = NSURLRequest(URL: urlhandle)
var response: NSURLResponse?
var error: NSErrorPointer = nil
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error)
println("\n\(url)\n")
println("\(response)\n\n")
} else {
println("Bad URL: \(url)")
}
}
doGET("http://google.com")
doGET("https://na.api.pvp.net/api/lol/na/v1.2/champion/1?api_key=\(apikey)")
doGET("https://google.com")
我得到以下 errors/output:
http://google.com
Optional(<NSHTTPURLResponse: 0x7fcff2443d60> { URL: http://www.google.com/ } { status code: 200, headers {
"Accept-Ranges" = none;
"Alternate-Protocol" = "80:quic,p=0.08";
"Cache-Control" = "private, max-age=0";
"Content-Type" = "text/html; charset=ISO-8859-1";
Date = "Wed, 25 Feb 2015 23:13:45 GMT";
Expires = "-1";
Server = gws;
"Transfer-Encoding" = Identity;
Vary = "Accept-Encoding";
"X-Frame-Options" = SAMEORIGIN;
"X-XSS-Protection" = "1; mode=block";
} })
2015-02-25 16:13:45.357 URL Requests[36397:3779864] NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9807)
https://na.api.pvp.net/api/lol/na/v1.2/champion/1?api_key=<redacted>
nil
2015-02-25 16:13:45.402 URL Requests[36397:3779864] NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9807)
https://google.com
nil
如您所见,请求在 HTTP URL 上成功,但在安全 HTTPS URL 上失败。如何允许使用 HTTPS?
它可能无法解决 https 问题,但在将链接转换为 NSURL 之前,您应该始终使用 stringByAddingPercentEscapesUsingEncoding
"http://google.com".stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
"https://na.api.pvp.net/api/lol/na/v1.2/champion/1?api_key=any key".stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! // "https://na.api.pvp.net/api/lol/na/v1.2/champion/1?api_key=any%20key"
func doGET(link: String) {
if let url = NSURL(string: link.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!) {
var response: NSURLResponse?
var error: NSErrorPointer = nil
let data = NSURLConnection.sendSynchronousRequest(NSURLRequest(URL: url), returningResponse: &response, error: error)
println("\n\(url)\n")
println("\(response)\n\n")
} else {
println("Bad URL")
}
}
您的代码应该可以在 'normal' 环境中运行。但是正如您提到的那样,您在大学里,接受服务器证书时可能存在问题。所以我会建议你添加 NSURLConnectionDelegate
并添加以下两个方法。我从戈登的回答中得到了这个想法 here。
func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace) -> Bool {
return protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
}
func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge) {
challenge.sender.useCredential(NSURLCredential(forTrust: challenge.protectionSpace.serverTrust), forAuthenticationChallenge: challenge)
}
问题中的情况是另一种情况,但我认为您的服务器证书也有同样的问题。
感谢@Christian 和@Leonardo。这似乎是我自己机器上的 firewall/certificate 问题。现有代码在命令提示符 (swift /path/to/file
) 中运行完美,仅在 Xcode 中失败。我希望它最终能在 Xcode 中运行,但当我到达它时我会跨过那座桥。