Swift - 网络抽象层库Moya的使用详解3(请求成功、失败的结果处理)
作者:hangge | 2017-09-29 08:10
五、请求结果的处理
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)运行结果如下:
- 当数据请求成功时,将返回结果弹出显示:

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

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

全部评论(2)
站长, 你这个let json = try JSON(response.mapJSON()), JSON是什么方法
站长回复:(1)JSON()是SwiftyJSON库里面的方法,其实在我的Moya系列文章的第一篇就引入了:Swift - 网络抽象层库Moya的使用详解1(安装配置、基本用法)
nice .就是这个
站长回复::)