Alamofire4.0的封装,实现请求失败后的重连策略

2018-05-23  本文已影响77人  红茶绅士

协议介绍

主要使用了Alamofire4.0新增的两个协议RequestRetrier和RequestAdapter.

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)
}
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)
                }
        }
    }   
}

参考:
Alamofire4.0 迁移指南

上一篇下一篇

猜你喜欢

热点阅读