下载 JSON 数据在 NSHTTPURLResponse 失败
Downloading JSON data fails at NSHTTPURLResponse
我正在尝试使用 Swift 从 URL 和 return 的内容中获取 JSON 文件。但是,代码在以下代码中的 let httpResponse = response as! NSHTTPURLResponse
行失败。我在这一行遇到异常,Xcode 进入调试模式。
class func downloadJSONFile()->AnyObject
{
let requestURL: NSURL = NSURL(string: "http://www.learnswiftonline.com/Samples/subway.json")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
var json:AnyObject = ""
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
do{
json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
}catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
return json
}
我该如何解决这个问题?
有几个问题:
如果请求中有任何错误,response
将是 nil
,因此您尝试强制转换它会导致致命错误。处理网络响应时不要使用强制unwrapping/casting。
这里有一个更深层次的问题,您正试图从一个异步运行的方法中 return 数据。您应该将您的方法更改为不 return 任何东西,本身,而是提供一个完成处理程序,您可以通过它异步传回相关数据:
class func downloadJSONFile(completionHandler: @escaping (Any?) -> Void) {
let requestURL = URL(string: "http://www.learnswiftonline.com/Samples/subway.json")!
let urlRequest = URLRequest(url: requestURL)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest) { data, response, error in
// check for fundamental networking errors
guard
error == nil,
let data = data
else {
print(error ?? "Other error")
completionHandler(nil)
return
}
guard
let httpResponse = response as? HTTPURLResponse,
(200 ..< 300) ~= httpResponse.statusCode
else {
print("Invalid status code")
completionHandler(nil)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data)
completionHandler(json)
} catch let parseError {
print("Error parsing: \(parseError)")
completionHandler(nil)
}
}
task.resume()
}
然后使用完成处理程序调用它(或使用尾随闭包语法,如下所示):
APIClass.downloadJSONFile() { json in
guard json != nil else {
print("there was some problem")
return
}
// now you can use `json` here
dispatch_async(dispatch_get_main_queue()) {
// and if you're doing any model or UI updates, dispatch that back to the main queue
}
}
// but do not use `json` here, as the above runs asynchronously
注意,如果您想将错误信息返回给调用例程,您可以将其更改为也 return 错误信息,例如:
enum DownloadError: Error {
case networkError(Error)
case notHTTPResponse
case invalidHTTPResponse(Int)
case parseError(Error)
}
class func downloadJSONFile(completionHandler: @escaping (Result<Any, Error>) -> Void) {
let requestURL = URL(string: "http://www.learnswiftonline.com/Samples/subway.json")!
let urlRequest = URLRequest(url: requestURL)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest) { data, response, error in
if let error = error {
completionHandler(.failure(DownloadError.networkError(error)))
return
}
guard let httpResponse = response as? HTTPURLResponse, let data = data else {
completionHandler(.failure(DownloadError.notHTTPResponse))
return
}
guard 200 ..< 300 ~= httpResponse.statusCode else {
completionHandler(.failure(DownloadError.invalidHTTPResponse(httpResponse.statusCode)))
return
}
do {
let json = try JSONSerialization.jsonObject(with: data)
completionHandler(.success(json))
} catch let parseError {
completionHandler(.failure(DownloadError.parseError(parseError)))
}
}
task.resume()
}
而且,显然,调用将更改为采用两个参数:
APIClass.downloadJSONFile() { result in
switch result {
case .failure(let error):
print(error)
case .success(let value):
// and then it would be like before ...
}
}
在 iOS 9 及更高版本中使用 URLSession
时,它将不允许明文请求(即不允许“http”,默认情况下仅允许“https” ).您可以通过将以下内容添加到 info.plist
来强制该应用允许非 https 请求。有关详细信息,请参阅
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>learnswiftonline.com</key>
<dict>
<!--Include to allow subdomains-->
<key>NSIncludesSubdomains</key>
<true/>
<!--Include to allow HTTP requests-->
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<!--Include to specify minimum TLS version-->
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
我正在尝试使用 Swift 从 URL 和 return 的内容中获取 JSON 文件。但是,代码在以下代码中的 let httpResponse = response as! NSHTTPURLResponse
行失败。我在这一行遇到异常,Xcode 进入调试模式。
class func downloadJSONFile()->AnyObject
{
let requestURL: NSURL = NSURL(string: "http://www.learnswiftonline.com/Samples/subway.json")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
var json:AnyObject = ""
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
do{
json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
}catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
return json
}
我该如何解决这个问题?
有几个问题:
如果请求中有任何错误,
response
将是nil
,因此您尝试强制转换它会导致致命错误。处理网络响应时不要使用强制unwrapping/casting。这里有一个更深层次的问题,您正试图从一个异步运行的方法中 return 数据。您应该将您的方法更改为不 return 任何东西,本身,而是提供一个完成处理程序,您可以通过它异步传回相关数据:
class func downloadJSONFile(completionHandler: @escaping (Any?) -> Void) { let requestURL = URL(string: "http://www.learnswiftonline.com/Samples/subway.json")! let urlRequest = URLRequest(url: requestURL) let session = URLSession.shared let task = session.dataTask(with: urlRequest) { data, response, error in // check for fundamental networking errors guard error == nil, let data = data else { print(error ?? "Other error") completionHandler(nil) return } guard let httpResponse = response as? HTTPURLResponse, (200 ..< 300) ~= httpResponse.statusCode else { print("Invalid status code") completionHandler(nil) return } do { let json = try JSONSerialization.jsonObject(with: data) completionHandler(json) } catch let parseError { print("Error parsing: \(parseError)") completionHandler(nil) } } task.resume() }
然后使用完成处理程序调用它(或使用尾随闭包语法,如下所示):
APIClass.downloadJSONFile() { json in guard json != nil else { print("there was some problem") return } // now you can use `json` here dispatch_async(dispatch_get_main_queue()) { // and if you're doing any model or UI updates, dispatch that back to the main queue } } // but do not use `json` here, as the above runs asynchronously
注意,如果您想将错误信息返回给调用例程,您可以将其更改为也 return 错误信息,例如:
enum DownloadError: Error { case networkError(Error) case notHTTPResponse case invalidHTTPResponse(Int) case parseError(Error) } class func downloadJSONFile(completionHandler: @escaping (Result<Any, Error>) -> Void) { let requestURL = URL(string: "http://www.learnswiftonline.com/Samples/subway.json")! let urlRequest = URLRequest(url: requestURL) let session = URLSession.shared let task = session.dataTask(with: urlRequest) { data, response, error in if let error = error { completionHandler(.failure(DownloadError.networkError(error))) return } guard let httpResponse = response as? HTTPURLResponse, let data = data else { completionHandler(.failure(DownloadError.notHTTPResponse)) return } guard 200 ..< 300 ~= httpResponse.statusCode else { completionHandler(.failure(DownloadError.invalidHTTPResponse(httpResponse.statusCode))) return } do { let json = try JSONSerialization.jsonObject(with: data) completionHandler(.success(json)) } catch let parseError { completionHandler(.failure(DownloadError.parseError(parseError))) } } task.resume() }
而且,显然,调用将更改为采用两个参数:
APIClass.downloadJSONFile() { result in switch result { case .failure(let error): print(error) case .success(let value): // and then it would be like before ... } }
在 iOS 9 及更高版本中使用
URLSession
时,它将不允许明文请求(即不允许“http”,默认情况下仅允许“https” ).您可以通过将以下内容添加到info.plist
来强制该应用允许非 https 请求。有关详细信息,请参阅<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>learnswiftonline.com</key> <dict> <!--Include to allow subdomains--> <key>NSIncludesSubdomains</key> <true/> <!--Include to allow HTTP requests--> <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> <true/> <!--Include to specify minimum TLS version--> <key>NSTemporaryExceptionMinimumTLSVersion</key> <string>TLSv1.1</string> </dict> </dict> </dict>