Alamofire4.0的封装,实现请求失败后的重连策略
2018-05-23 本文已影响77人
红茶绅士
协议介绍
主要使用了Alamofire4.0新增的两个协议RequestRetrier和RequestAdapter.
- RequestRetrier(请求重连)
public typealias RequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval) -> Void
public protocol RequestRetrier {
func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion)
}
它可以在Request
遇到 Error
的时候, 在指定的延迟之后重新发起请求.
注意事项:为了避免无限重连,需要对请求地址做最大重连限制
class OAuth2Handler: RequestAdapter, RequestRetrier {
public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: RequestRetryCompletion) {
if let response = request.task.response as? HTTPURLResponse, response.statusCode == 401 {
completion(true, 1.0) // 1秒后重试
} else {
completion(false, 0.0) // 不重连
}
}
}
let sessionManager = SessionManager()
sessionManager.retrier = OAuth2Handler()
sessionManager.request(urlString).responseJSON { response in
debugPrint(response)
}
- RequestAdapter(请求适配器)
public protocol RequestAdapter {
func adapt(_ urlRequest: URLRequest) throws -> URLRequest
}
它可以让每一个 SessionManager
生成的 Request
都在生成之前被解析并且按照规则适配. 一个使用适配器很典型的场景就是给请求添加一个 Authorization
的请求头.
class AccessTokenAdapter: RequestAdapter {
private let accessToken: String
init(accessToken: String) {
self.accessToken = accessToken
}
func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
var urlRequest = urlRequest
if urlRequest.urlString.hasPrefix("https://httpbin.org") {
urlRequest.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
}
return urlRequest
}
}
let sessionManager = SessionManager()
sessionManager.adapter = AccessTokenAdapter(accessToken: "1234")
sessionManager.request("https://httpbin.org/get")
如果一个 Error
在适配过程中产生的话, 它会逐层抛出, 最后传递到 Request
的请求回调里.
封装HTTPSessionManager
注意事项:
RequestRetrier
协议的回调是请求失败后才会进入,如果是请求成功后,需要对个别错误码进行重连操作,可以参考validate
import Alamofire
import SwiftyJSON
/// 数据回调
public typealias HTTPSuccessBlock = (_ result : JSON) -> Void
public typealias HTTPFailureBlock = (_ error : HTTPErrorCode) -> Void
public enum HTTPErrorCode : Int, Error {
case SystemError = 4000 //参数错误
case UnknownError = 5000 //未知错误
.
.
.
}
class HTTPSessionManager: NSObject {
/// Alamofire
private var manager : SessionManager {
let manager = SessionManager.default
manager.retrier = OAuth2Handler()
manager.adapter = OAuth2Handler()
return manager
}
}
extension HTTPSessionManager {
public func request(methodType : HTTPMethod, urlString : String, parameters : [String: Any]?, successBlock : @escaping HTTPSuccessBlock, failureBlock : @escaping HTTPFailureBlock) {
manager.request(urlString, method: methodType, parameters: requestJson, encoding: JSONEncoding.default, headers: SessionManager.defaultHTTPHeaders)
.responseJSON { (json) in
// 返回数据处理
switch json.result {
case .success(let result):
let retCode = JSON(result)["retCode"].intValue
if retCode == 成功 {
successBlock(JSON(result))
} else {
guard let errorCode = HTTPErrorCode(rawValue: retCode) else {
return failureBlock(HTTPErrorCode.UnknownError)
}
return failureBlock(errorCode)
}
case .failure(let error):
failureBlock(HTTPErrorCode.UnknownError)
}
}
}
}