Alamofire高级用法

基础用法和高级用法的区别:

  • 基础用法:
    • AF.request()AF.download()AF.upload() 发起请求 (AF = Session.default
    • 配置参数中的 parameters、encoder、headers
    • 以及对response的处理
  • 高级用法:
    • 自定义 Session
      • 不使用Session.default, 自定义Session
    • 组装 URLRequest
    • 自定义 Requests
      • AF.request()AF.download()AF.upload() 本质上都是组装一个Request
      • 自定义 Requests 就是不通过这些便利方法生成,自己组装Request

自定义 Session

创建自定义Session实例
public convenience init(configuration: URLSessionConfiguration = URLSessionConfiguration.af.default,
                            delegate: SessionDelegate = SessionDelegate(),
                            rootQueue: DispatchQueue = DispatchQueue(label: "org.alamofire.session.rootQueue"),
                            startRequestsImmediately: Bool = true,
                            requestQueue: DispatchQueue? = nil,
                            serializationQueue: DispatchQueue? = nil,
                            interceptor: RequestInterceptor? = nil,
                            serverTrustManager: ServerTrustManager? = nil,
                            redirectHandler: RedirectHandler? = nil,
                            cachedResponseHandler: CachedResponseHandler? = nil,
                            eventMonitors: [EventMonitor] = [])
1. Session配置(URLSessionConfiguration

默认值 URLSessionConfiguration.af.default 提供了Accept-Encoding, Accept-Language, User-Agent

这3个请求头。源码如下:

public static var `default`: URLSessionConfiguration {
    let configuration = URLSessionConfiguration.default
    configuration.headers = .default

    return configuration
}
public extension HTTPHeaders {
    static let `default`: HTTPHeaders = [.defaultAcceptEncoding,
                                         .defaultAcceptLanguage,
                                         .defaultUserAgent]
}
/// Accept-Encoding
public static let defaultAcceptEncoding: HTTPHeader = {
    let encodings: [String]
    if #available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *) {
        encodings = ["br", "gzip", "deflate"]
    } else {
        encodings = ["gzip", "deflate"]
    }

    return .acceptEncoding(encodings.qualityEncoded())
}()

/// Accept-Language
public static let defaultAcceptLanguage: HTTPHeader = {
    .acceptLanguage(Locale.preferredLanguages.prefix(6).qualityEncoded())
}()

/// User-Agent
public static let defaultUserAgent: HTTPHeader = {
    let info = Bundle.main.infoDictionary
    let executable = (info?[kCFBundleExecutableKey as String] as? String) ??
        (ProcessInfo.processInfo.arguments.first?.split(separator: "/").last.map(String.init)) ??
        "Unknown"
    let bundle = info?[kCFBundleIdentifierKey as String] as? String ?? "Unknown"
    let appVersion = info?["CFBundleShortVersionString"] as? String ?? "Unknown"
    let appBuild = info?[kCFBundleVersionKey as String] as? String ?? "Unknown"

    let osNameVersion: String = {
        let version = ProcessInfo.processInfo.operatingSystemVersion
        let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
        let osName: String = {
            #if os(iOS)
            return "iOS"
            #elseif os(watchOS)
            return "watchOS"
            #elseif os(tvOS)
            return "tvOS"
            #elseif os(macOS)
            return "macOS"
            #elseif os(Linux)
            return "Linux"
            #elseif os(Windows)
            return "Windows"
            #else
            return "Unknown"
            #endif
        }()

        return "\(osName) \(versionString)"
    }()

    let alamofireVersion = "Alamofire/\(version)"

    let userAgent = "\(executable)/\(appVersion) (\(bundle); build:\(appBuild); \(osNameVersion)) \(alamofireVersion)"

    return .userAgent(userAgent)
}()

URLSessionConfiguration 是Apple URL加载系统中的类,它提供了3种便捷使用的实例

// 永久性的磁盘的缓存并将凭据存储在用户的钥匙串中
class var `default`: URLSessionConfiguration
// 不会将任何数据存储到磁盘中,所有缓存,凭据存储等都保存在RAM中并与会话相关联。因此,当您的应用程序使会话无效时,它们将自动清除
class var ephemeral: URLSessionConfiguration
// 后台会话, 类似于默认会话,但是在单独的进程处理所有数据传输
class func background(withIdentifier: String) -> URLSessionConfiguration

挑选一些重要的可配置的参数

open var requestCachePolicy: NSURLRequest.CachePolicy
open var timeoutIntervalForRequest: TimeInterval
open var timeoutIntervalForResource: TimeInterval
open var allowsCellularAccess: Bool
open var sessionSendsLaunchEvents: Bool
open var httpShouldSetCookies: Bool
open var httpCookieAcceptPolicy: HTTPCookie.AcceptPolicy
open var httpAdditionalHeaders: [AnyHashable : Any]?
open var httpCookieStorage: HTTPCookieStorage?
open var urlCredentialStorage: URLCredentialStorage?
open var urlCache: URLCache?
open var protocolClasses: [AnyClass]?
2. SessionDelegate

SessionDelegate 是对URLSessionDelegate和相关的协议回调的封装

3. startRequestsImmediately

立即执行请求

4. RequestInterceptor

RequestInterceptor 协议(RequestAdapter & RequestRetrier)提供了请求适配器和重试功能

  • RequestAdapter 协议 功能非常有用,比如说设置请求头Token, 或其他修改Request操作
  • RequestRetrier 请求失败重试

示例:

struct CustomRequestInterceptor: RequestInterceptor {
    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) {
        var request = urlRequest
        request.headers.add(.authorization(bearerToken: accessToken))
        completion(.success(request))
    }
    
    func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
       if request.retryCount < retryLimit,
       let httpMethod = request.request?.method,
       retryableHTTPMethods.contains(httpMethod),
       shouldRetry(response: request.response, error: error) {
        let timeDelay = pow(Double(exponentialBackoffBase), Double(request.retryCount)) * exponentialBackoffScale
        completion(.retryWithDelay(timeDelay))
    } else {
        completion(.doNotRetry)
    }
}
AF.request("https://httpbin.org/get", interceptor: CustomRequestInterceptor()).responseJSON { response in
    debugPrint(response)
}
5. CachedResponseHandler

缓存处理器

Alamofire 提供了一个默认的缓存处理器,源码如下:

public struct ResponseCacher {
    /// Defines the behavior of the `ResponseCacher` type.
    public enum Behavior {
        /// Stores the cached response in the cache.
        case cache
        /// Prevents the cached response from being stored in the cache.
        case doNotCache
        /// Modifies the cached response before storing it in the cache.
        case modify((URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)
    }

    /// Returns a `ResponseCacher` with a follow `Behavior`.
    public static let cache = ResponseCacher(behavior: .cache)
    /// Returns a `ResponseCacher` with a do not follow `Behavior`.
    public static let doNotCache = ResponseCacher(behavior: .doNotCache)

    /// The `Behavior` of the `ResponseCacher`.
    public let behavior: Behavior

    /// Creates a `ResponseCacher` instance from the `Behavior`.
    ///
    /// - Parameter behavior: The `Behavior`.
    public init(behavior: Behavior) {
        self.behavior = behavior
    }
}

extension ResponseCacher: CachedResponseHandler {
    public func dataTask(_ task: URLSessionDataTask,
                         willCacheResponse response: CachedURLResponse,
                         completion: @escaping (CachedURLResponse?) -> Void) {
        switch behavior {
        case .cache:
            completion(response)
        case .doNotCache:
            completion(nil)
        case let .modify(closure):
            let response = closure(task, response)
            completion(response)
        }
    }
}

使用示例:

/// 使用cache模式缓存数据
Session( cachedResponseHandler: ResponseCacher.cache)
.request("https://httpbin.org/get")
.responseJSON { response in
    debugPrint(response)
}
6. RedirectHandler

重定向处理器

Alamofire 提供了一个默认的重定向处理器,源码如下:

public struct Redirector {
    /// Defines the behavior of the `Redirector` type.
    public enum Behavior {
        /// Follow the redirect as defined in the response.
        case follow
        /// Do not follow the redirect defined in the response.
        case doNotFollow
        /// Modify the redirect request defined in the response.
        case modify((URLSessionTask, URLRequest, HTTPURLResponse) -> URLRequest?)
    }

    /// Returns a `Redirector` with a `.follow` `Behavior`.
    public static let follow = Redirector(behavior: .follow)
    /// Returns a `Redirector` with a `.doNotFollow` `Behavior`.
    public static let doNotFollow = Redirector(behavior: .doNotFollow)

    /// The `Behavior` of the `Redirector`.
    public let behavior: Behavior

    /// Creates a `Redirector` instance from the `Behavior`.
    ///
    /// - Parameter behavior: The `Behavior`.
    public init(behavior: Behavior) {
        self.behavior = behavior
    }
}

// MARK: -

extension Redirector: RedirectHandler {
    public func task(_ task: URLSessionTask,
                     willBeRedirectedTo request: URLRequest,
                     for response: HTTPURLResponse,
                     completion: @escaping (URLRequest?) -> Void) {
        switch behavior {
        case .follow:
            completion(request)
        case .doNotFollow:
            completion(nil)
        case let .modify(closure):
            let request = closure(task, request, response)
            completion(request)
        }
    }
}

使用示例:

/// 使用follow模式
Session(redirectHandler: Redirector(behavior: .follow))
.request("https://httpbin.org/get")
.responseJSON { response in
    debugPrint(response)
}
7. EventMonitor

请求代理回调处理,包含 URLSessionDelegate, URLSessionTaskDelegate, 和URLSessionDownloadDelegate

自定义 Requests

  • AF.request() -> DataRequestAF.download() -> DownloadRequestAF.upload() -> UploadRequest 本质上都是组装一个Request
  • 自定义 Requests 就是不通过这些便利方法生成,自己组装Request

组装 URLRequest

Session 中 的

open func request(_ convertible: URLConvertible,
                      method: HTTPMethod = .get,
                      parameters: Parameters? = nil,
                      encoding: ParameterEncoding = URLEncoding.default,
                      headers: HTTPHeaders? = nil,
                      interceptor: RequestInterceptor? = nil,
                      requestModifier: RequestModifier? = nil) -> DataRequest {
    let convertible = RequestConvertible(url: convertible,
                                         method: method,
                                         parameters: parameters,
                                         encoding: encoding,
                                         headers: headers,
                                         requestModifier: requestModifier)

    return request(convertible, interceptor: interceptor)
}

本质是调用了下面的API

open func request(_ urlRequest: URLRequestConvertible, 
                  interceptor: RequestInterceptor? = nil) -> DataRequest

RequestConvertible 源码如下

struct RequestConvertible: URLRequestConvertible {
    let url: URLConvertible
    let method: HTTPMethod
    let parameters: Parameters?
    let encoding: ParameterEncoding
    let headers: HTTPHeaders?
    let requestModifier: RequestModifier?

    func asURLRequest() throws -> URLRequest {
        var request = try URLRequest(url: url, method: method, headers: headers)
        try requestModifier?(&request)

        return try encoding.encode(request, with: parameters)
    }
}

我们可以实现URLRequestConvertible 来完成组装URLRequest然后调用request(_ convertible: URLRequestConvertible, interceptor: RequestInterceptor? = nil)发起请求

你可能感兴趣的:(Alamofire高级用法)