[英]cast server response in AFError
What I'm trying to achieve is that I have a NetworkManager
that handles the request
's to the server, and handle the error through AFError
.我想要实现的是我有一个NetworkManager
来处理对服务器的request
,并通过AFError
处理错误。 However sometimes when the server response is 4xx, there is a custom message with that response which I want to show that to the user But don't know how to implement it.但是,有时当服务器响应为 4xx 时,会有一条带有该响应的自定义消息,我想向用户展示但不知道如何实现它。
This is my NetworkManager
这是我的NetworkManager
static let shared:NetworkManager = {
return NetworkManager()
}()
typealias completionHandler = ((Result<Data, AFError>) ->Void)
func handleAFrequest(request: DataRequest,completion: @escaping completionHandler) {
request.validate(statusCode: 200..<300)
request.responseJSON { (response) in
switch response.result {
case .success(_):
if let data = response.data {
completion(.success(data))
}
case .failure(let error):
print(error.localizedDescription)
switch error {
case .invalidURL(let url):
print("Invalid URL: \(url) - \(error.localizedDescription)")
completion(.failure(.invalidURL(url: URL)))
case .responseValidationFailed(let reason):
print("Response validation failed: \(error.localizedDescription); Reason:\(reason)")
completion(.failure(.responseValidationFailed(reason: reason)))
I want to be able to cast server response in addition to the error, and show Message
of the response to the user.除了错误之外,我还希望能够投射服务器响应,并向用户显示响应Message
。 Server Response example when StatusCode is 4xx: StatusCode 为 4xx 时的服务器响应示例:
{
"data":
"code":401;
"Message":"Phone Invalid"
}
I have parsed api errors in many of my projects.我已经在我的许多项目中解析了 api 错误。 I believe there is a better alternative to handle the showing or errors if any, to the user.我相信有更好的选择来处理用户的显示或错误(如果有)。 Please see my code, in it, if there is a error I show it in a toast.请查看我的代码,如果有错误,我会在祝酒词中显示。 Showing in a toast is the not focal point but you can see how I handle the error case in my code and it has never failed.在 toast 中显示不是重点,但您可以看到我如何处理代码中的错误情况并且它从未失败过。 Please change the params accordingly to your api call请根据您的 api 调用更改参数
func postMethod(mylist: [String:Any]) {
print(K.APIUrl)
print(K.port)
AF.request("\(K.urlFromUrlField!):\(K.configPort)/snhttp-01?", method: .put, parameters: mylist)
.authenticate(username: username, password: password)
.response { response in
switch response.result {
case .success:
print("\nValidation Successful from put method")
print(response.result)
print(response.value as Any)
//get xml code and error msg if any
if let response = response.data{
let xml = XML.parse(response)
print(xml)
print("\nThis is the data sent to the server: \(mylist["data"] ?? "No data in data key of the parameter")" )
let code = xml.Response.Code.text ?? "No code value in response"
let responseMessage = xml.Response.Message.text ?? "No message returned from server"
print("\nCode value from server: \(code)")
print("\nResponse message from server: \(responseMessage)")
}
else{
print("\nSuccess block: Request Successfully sent, BUT there was nothing from the server to unwrap! / nothing sent back from the server\nThis is the data sent to the server: \(mylist["data"] ?? "No data in data key of the parameter")")
}
case let .failure(error):
if let response = response.data {
let xml = XML.parse(response)
let code = xml.Response.Code.text ?? "\nNo code value in response"
let responseMessage = xml.Response.Message.text ?? "No message returned from server"
print("\nCode value from server: \(code)")
print("\nResponse message from server: \(responseMessage)")
print(error)
}
else {
print("\nFailure Block: A connection to the server could not be established")
}
}}
}
This code parses the xml from the api.此代码从 api 解析 xml。 However you can discard that and just focus on how I handle the response and consequently the error.但是,您可以放弃它,只关注我如何处理响应以及错误。
This is the solution that works for me.这是对我有用的解决方案。
All you need to do is create a custom error type:您需要做的就是创建一个自定义错误类型:
struct APIError: Error, Decodable {
let status: Int?
let message: String?
let key: String?
}
Then call Alamofire, which will return an AFDataResponse which you can parse:然后调用 Alamofire,它会返回一个可以解析的AFDataResponse :
func performRequest<T: Decodable>(route: APIRouter, completion: @escaping (APIResponse<T>) -> Void) {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
AF.request(route)
.validate()
.responseDecodable(decoder: decoder, emptyResponseCodes: [200, 201]) { (response: AFDataResponse<T>) in
self.parseResponse(response: response, completion: completion)
}
}
Parsing is done like this:解析是这样完成的:
private func parseResponse<T: Decodable>(response: AFDataResponse<T>, completion: @escaping (APIResponse<T>) -> Void) {
switch response.result {
case .success(let data):
completion(APIResponse<T>.success(data))
case .failure(let error):
if let data = response.data,
// THIS IS WHERE YOU CAST AFError TO YOUR CUSTOM APIError
let apiError = try? JSONDecoder().decode(APIError.self, from: data) {
completion(APIResponse.failure(apiError))
} else {
completion(APIResponse.failure(error))
}
}
}
Hope this helps!希望这可以帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.