如果远程 GET 请求失败,如何定义回退情况?
How to define a fallback case if a remote GET request fails?
我最近开始 iOS 开发,目前正在为现有应用程序添加新功能。对于此功能,我需要从 Web 服务器获取 JSON
文件。但是,如果服务器无法访问(没有 internet/server unavailable/etc),则需要使用本地 JSON
。
在我当前的实现中,我尝试使用 do catch
块,但如果没有互联网连接,应用程序就会挂起而不是转到 catch
块。 JSON
解析和本地数据读取似乎工作正常,问题可能出在 GET
方法中,因为我试图将 return JSON
数据的回调定义为单独的变量,但我不确定这是否是正确的方法。
处理这种情况的最佳方法是什么?
let url = URL(string: "https://jsontestlocation.com") // test JSON
do {
// make a get request, get the result as a callback
let _: () = getRemoteJson(requestUrl: url!, requestType: "GET") {
remoteJson in
performOnMainThread {
self.delegate.value?.didReceiveJson(.success(self.parseJson(jsonData: remoteJson!)!))
}
}
}
catch {
let localFile = readLocalFile(forName: "local_json_file")
let localJson = parseJson(jsonData: localFile!)
if let localJson = localJson {
self.delegate.value?.didReceiveJson(.success(localJson))
}
}
getRemoteJson()
实施:
private func getRemoteJson(requestUrl: URL, requestType: String, completion: @escaping (Data?) -> Void) {
// Method which returns a JSON questionnaire from a remote API
var request = URLRequest(url: requestUrl) // create the request
request.httpMethod = requestType
// make the request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// check if there is any error
if let error = error {
print("GET request error: \(error)")
}
// print the HTTP response
if let response = response as? HTTPURLResponse {
print("GET request status code: \(response.statusCode)")
}
guard let data = data else {return} // return nil if no data
completion(data) // return
}
task.resume() // resumes the task, if suspended
}
parseJson()
实施:
private func parseJson(jsonData: Data) -> JsonType? {
// Method definition
do {
let decodedData = try JSONDecoder().decode(JsonType.self, from: jsonData)
return decodedData
} catch {
print(error)
}
return nil
}
func NetworkCheck() -> 布尔 {
var isReachable = false
let reachability = Reachability()
print(reachability.status)
if reachability.isOnline {
isReachable = true
// True, when on wifi or on cellular network.
}
else
{
// "Sorry! Internet Connection appears to be offline
}
return isReachable
}
在您的 API 请求之前调用 NetworkCheck()。如果它 returns 为假,请阅读您的本地 json 文件。如果为真,则进行远程 API 调用。
万一在远程 API 调用之后,任何使用 HTTP header 响应代码的失败检查。
如果让 httpStatus = 响应为? HTTPURLResponse, httpStatus.statusCode != 200 {
}
我认为您需要阻止请求在等待响应时挂起。该应用程序可能 运行 连接不佳并且能够获取部分但不是全部数据,在这种情况下您可能希望故障转移到本地 JSON.
我认为您可以粗略地使用现有的,但按照此处所述在 URLSession 上添加超时配置:
如果您不必使用具有可达性、错误处理、请求重试等的复杂逻辑,只需 return nil
在数据任务、HTTP 和无数据错误的情况下完成:
func getRemoteJson(requestUrl: URL, requestType: String, completion: @escaping (Data?) -> Void) {
var request = URLRequest(url: requestUrl)
request.httpMethod = requestType
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Task error
guard error == nil else {
print("GET request error: \(error!)")
completion(nil)
return
}
// HTTP error
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
print("GET request failed: \(response!.description)")
completion(nil)
return
}
// No data
guard let data = data else {
completion(nil)
return
}
completion(data)
}
task.resume()
}
let url = URL(string: "https://jsontestlocation.com")!
getRemoteJson(requestUrl: url, requestType: "GET") { remoteJson in
if let json = remoteJson {
print(json)
...
}
else {
print("Request failed")
...
}
}
我最近开始 iOS 开发,目前正在为现有应用程序添加新功能。对于此功能,我需要从 Web 服务器获取 JSON
文件。但是,如果服务器无法访问(没有 internet/server unavailable/etc),则需要使用本地 JSON
。
在我当前的实现中,我尝试使用 do catch
块,但如果没有互联网连接,应用程序就会挂起而不是转到 catch
块。 JSON
解析和本地数据读取似乎工作正常,问题可能出在 GET
方法中,因为我试图将 return JSON
数据的回调定义为单独的变量,但我不确定这是否是正确的方法。
处理这种情况的最佳方法是什么?
let url = URL(string: "https://jsontestlocation.com") // test JSON
do {
// make a get request, get the result as a callback
let _: () = getRemoteJson(requestUrl: url!, requestType: "GET") {
remoteJson in
performOnMainThread {
self.delegate.value?.didReceiveJson(.success(self.parseJson(jsonData: remoteJson!)!))
}
}
}
catch {
let localFile = readLocalFile(forName: "local_json_file")
let localJson = parseJson(jsonData: localFile!)
if let localJson = localJson {
self.delegate.value?.didReceiveJson(.success(localJson))
}
}
getRemoteJson()
实施:
private func getRemoteJson(requestUrl: URL, requestType: String, completion: @escaping (Data?) -> Void) {
// Method which returns a JSON questionnaire from a remote API
var request = URLRequest(url: requestUrl) // create the request
request.httpMethod = requestType
// make the request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// check if there is any error
if let error = error {
print("GET request error: \(error)")
}
// print the HTTP response
if let response = response as? HTTPURLResponse {
print("GET request status code: \(response.statusCode)")
}
guard let data = data else {return} // return nil if no data
completion(data) // return
}
task.resume() // resumes the task, if suspended
}
parseJson()
实施:
private func parseJson(jsonData: Data) -> JsonType? {
// Method definition
do {
let decodedData = try JSONDecoder().decode(JsonType.self, from: jsonData)
return decodedData
} catch {
print(error)
}
return nil
}
func NetworkCheck() -> 布尔 {
var isReachable = false
let reachability = Reachability()
print(reachability.status)
if reachability.isOnline {
isReachable = true
// True, when on wifi or on cellular network.
}
else
{
// "Sorry! Internet Connection appears to be offline
}
return isReachable
}
在您的 API 请求之前调用 NetworkCheck()。如果它 returns 为假,请阅读您的本地 json 文件。如果为真,则进行远程 API 调用。
万一在远程 API 调用之后,任何使用 HTTP header 响应代码的失败检查。
如果让 httpStatus = 响应为? HTTPURLResponse, httpStatus.statusCode != 200 {
}
我认为您需要阻止请求在等待响应时挂起。该应用程序可能 运行 连接不佳并且能够获取部分但不是全部数据,在这种情况下您可能希望故障转移到本地 JSON.
我认为您可以粗略地使用现有的,但按照此处所述在 URLSession 上添加超时配置:
如果您不必使用具有可达性、错误处理、请求重试等的复杂逻辑,只需 return nil
在数据任务、HTTP 和无数据错误的情况下完成:
func getRemoteJson(requestUrl: URL, requestType: String, completion: @escaping (Data?) -> Void) {
var request = URLRequest(url: requestUrl)
request.httpMethod = requestType
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Task error
guard error == nil else {
print("GET request error: \(error!)")
completion(nil)
return
}
// HTTP error
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
print("GET request failed: \(response!.description)")
completion(nil)
return
}
// No data
guard let data = data else {
completion(nil)
return
}
completion(data)
}
task.resume()
}
let url = URL(string: "https://jsontestlocation.com")!
getRemoteJson(requestUrl: url, requestType: "GET") { remoteJson in
if let json = remoteJson {
print(json)
...
}
else {
print("Request failed")
...
}
}