Swift - 网络抽象层库Moya的使用详解3(请求成功、失败的结果处理)
五、请求结果的处理
1,成功、失败响应的判断
(1)之前的样例中我们只处理数据成功返回的情况,其实 Moya 会将 Alamofire 成功或失败的响应包裹在 Result 枚举中返回,具体值如下:
- .success(Moya.Response):成功的情况。我们可以从 Moya.Response 中得到返回数据(data)和状态(status )
- .failure(MoyaError):失败的情况。这里的失败指的是服务器没有收到请求(例如可达性/连接性错误)或者没有发送响应(例如请求超时)。我们可以在这里设置个延迟请求,过段时间重新发送请求。
DouBanProvider.request(.playlist(channelId)) { result in switch result { case let .success(response): let statusCode = response.statusCode // 响应状态码:200, 401, 500... let data = response.data // 响应数据 //继续做一些其它事情.... case let .failure(error): //错误处理.... break } }
(2)对于 .failure(error) 情况下,我们还可以通过 switch 语句判断具体的 MoyaError 错误类型:
case let .failure(error): switch error { case .imageMapping(let response): print("错误原因:\(error.errorDescription ?? "")") print(response) case .jsonMapping(let response): print("错误原因:\(error.errorDescription ?? "")") print(response) case .statusCode(let response): print("错误原因:\(error.errorDescription ?? "")") print(response) case .stringMapping(let response): print("错误原因:\(error.errorDescription ?? "")") print(response) case .underlying(let error, let response): print("错误原因:\(error.errorDescription ?? "")") print(error) print(response as Any) case .requestMapping: print("错误原因:\(error.errorDescription ?? "")") print("nil") }
比如当我们在没有网络的情况下发起请求,控制台输出如下(走的是 .underlying 分支):

2,过滤正确的状态码
除了连接超时这样的网络问题会返回 .failure,像是服务器报错(404)、请求未授权(401)等都是返回 .success 的。这样我们还需要根据状态码来判断返回数据是否是正确的。
Moya.Response 本身就提供了下面两个方法来过滤 response 响应:
- filterSuccessfulStatusCodes():返回状态码为 200 - 299 的响应
- filterSuccessfulStatusAndRedirectCodes():返回状态码为 200 - 399 的响应
DouBanProvider.request(.playlist(channelId)) { result in switch result { case let .success(response): do { //过滤成功的状态码响应 try response.filterSuccessfulStatusCodes() let data = try response.mapJSON() //继续做一些其它事情.... } catch { //处理错误状态码的响应... } case let .failure(error): //错误处理.... break } }
3,封装一个请求/结果处理的适配器
(1)虽然 Mayo 使用起来很方便,但如果每次都要对响应结果进行判断(连接是否成功、响应状态码是否正确)还是略显麻烦。我们可以自行定义一个适配器(adapter),将请求和结果的判断处理都封装起来。然后通过三个回调函数返回相应的结果,这三个回调函数分别对应三种响应情况:
- success:服务器连接成功,且数据正确返回(同时会自动将数据转换成 JSON 对象,方便使用)
- error:服务器连接成功,但数据返回错误(同时会返回错误信息)
- failure :服务器连接不上,网络异常等(同时会返回错误信息。必要的话,还可以在此增加自动重新请求的机制。)
import Moya struct Network { static let provider = MoyaProvider<DouBan>() static func request( _ target: DouBan, success successCallback: @escaping (JSON) -> Void, error errorCallback: @escaping (Int) -> Void, failure failureCallback: @escaping (MoyaError) -> Void ) { provider.request(target) { result in switch result { case let .success(response): do { //如果数据返回成功则直接将结果转为JSON try response.filterSuccessfulStatusCodes() let json = try JSON(response.mapJSON()) successCallback(json) } catch let error { //如果数据获取失败,则返回错误状态码 errorCallback((error as! MoyaError).response!.statusCode) } case let .failure(error): //如果连接异常,则返沪错误信息(必要时还可以将尝试重新发起请求) //if target.shouldRetry { // retryWhenReachable(target, successCallback, errorCallback, // failureCallback) //} //else { failureCallback(error) //} } } } }
(2)这样我们直接使用这个 adapter 请求数据,代码会清爽许多。
Network.request(.playlist(channelId), success: { json in //获取歌曲信息 let music = json["song"].arrayValue[0] let artist = music["artist"].stringValue let title = music["title"].stringValue let message = "歌手:\(artist)\n歌曲:\(title)" //将歌曲信息弹出显示 self.showAlert(title: channelName, message: message) }, error: { statusCode in //服务器报错等问题 print("请求错误!错误码:\(statusCode)") }, failure: { error in //没有网络等问题 print("请求失败!错误信息:\(error.errorDescription ?? "")") })
(3)运行结果如下:
- 当数据请求成功时,将返回结果弹出显示:

- 当数据请求错误时,打印出错误的状态码:

- 当连接失败时,打印出错误信息:

站长, 你这个let json = try JSON(response.mapJSON()), JSON是什么方法
nice .就是这个