Alamofire 高级使用文档

2 阅读12分钟

原文链接:github.com/Alamofire/A…说明:本文是 Alamofire 的高级文档,讲解自定义会话、拦截器、证书校验、路由封装、Combine / Swift Concurrency 等进阶能力。

Alamofire 构建于 URLSession 和 Foundation 的 URL 加载系统之上。为充分发挥框架能力,建议你熟悉底层网络栈的概念与能力。

推荐阅读官方资料

  • URL Loading System 编程指南
  • URLSession 类参考文档
  • URLCache 类参考文档
  • URLAuthenticationChallenge 类参考文档

Session

Alamofire 的 Session 职责大体等价于它内部持有的 URLSession 实例:它提供 API 生成各类 Request 子类,封装不同的 URLSessionTask,同时封装一套配置,作用于该实例产生的所有请求。

Session 提供单例 default,AF 命名空间顶层 API 就是由它驱动。下面两行代码完全等价:

swift

AF.request("https://httpbin.org/get")

let session = Session.default
session.request("https://httpbin.org/get")

创建自定义 Session 实例

多数应用需要以各种方式自定义 Session 行为,最简单的方式是使用便捷构造器,将实例保存为全局单例供 App 各处使用。

swift

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] = []
)

该构造器可以自定义 Session 的全部基础行为。

使用 URLSessionConfiguration 创建 Session

想要定制底层 URLSession 的行为,可以传入自定义的 URLSessionConfiguration。推荐基于 URLSessionConfiguration.af.default 来修改,该默认配置已经预置了 Alamofire 的 Accept‑Encoding、Accept‑Language、User‑Agent 请求头;当然也可以传入任意配置。

swift

let configuration = URLSessionConfiguration.af.default
configuration.allowsCellularAccess = false
let session = Session(configuration: configuration)

不建议在 URLSessionConfiguration 里设置 Authorization、Content‑Type 这类请求头。应该通过请求的 headers 参数、ParameterEncoder 或者 RequestAdapter 来添加。根据 Apple 文档:配置对象一旦被交给 URLSession(Alamofire 中即初始化 Session)之后,再修改配置属性不会生效。

SessionDelegate

SessionDelegate 封装全部 URLSessionDelegate 及相关协议回调。同时它也是每个 Request 的状态提供者,让请求可以间接拿到所属 Session 的状态。SessionDelegate 可以传入自定义 FileManager,用于磁盘读写,例如上传、下载文件操作。

swift

let delegate = SessionDelegate(fileManager: .default)

startRequestsImmediately

默认情况下,Session 只要给请求添加至少一个响应回调,就会自动调用 resume() 启动请求。设置为 false,就必须手动调用每个 Request 的 resume()。

swift

let session = Session(startRequestsImmediately: false)

Session 的调度队列 DispatchQueue

默认 Session 使用同一个调度队列处理全部异步工作:包括 URLSession delegate 的底层队列、创建请求、响应序列化、Session/Request 内部状态变更。如果性能分析发现创建请求或者序列化响应成为瓶颈,可以为不同工作分配独立队列。

swift

let rootQueue = DispatchQueue(label: "com.app.session.rootQueue")
let requestQueue = DispatchQueue(label: "com.app.session.requestQueue")
let serializationQueue = DispatchQueue(label: "com.app.session.serializationQueue")

let session = Session(
    rootQueue: rootQueue,
    requestQueue: requestQueue,
    serializationQueue: serializationQueue
)

自定义 rootQueue 必须是串行队列;requestQueue、serializationQueue 可以串行或并行。没有性能问题优先使用串行。

添加 RequestInterceptor

RequestInterceptor 协议同时继承 RequestAdapter & RequestRetrier,提供强大的请求修改与重试能力。既可以作用于整个 Session,也可以单独作用于某一个请求。后面会详细介绍,内置实现如 RetryPolicy。

swift

let policy = RetryPolicy()
let session = Session(interceptor: policy)

添加 ServerTrustManager(服务端证书信任管理器)

iOS14 /tvOS14 /watchOS7 /macOS11+,Apple 已经在 Info.plist 原生支持证书锁定,优先使用系统能力,再考虑 Alamofire 的实现。

ServerTrustManager 维护域名与信任评估器的映射,用来定制 TLS 校验逻辑,支持证书锁定、公钥锁定、证书吊销校验。

swift

let manager = ServerTrustManager(evaluators: ["httpbin.org": PinnedCertificatesTrustEvaluator()])
let session = Session(serverTrustManager: manager)

添加 RedirectHandler(重定向处理器)

RedirectHandler 自定义 HTTP 重定向逻辑,支持 Session 全局设置,也可以单请求覆盖。Alamofire 提供实现类 Redirector。

swift

let redirector = Redirector(behavior: .follow)
let session = Session(redirectHandler: redirector)

添加 CachedResponseHandler(缓存处理器)

CachedResponseHandler 自定义响应缓存逻辑,全局或单请求均可配置,内置实现 ResponseCacher。

swift

let cacher = ResponseCacher(behavior: .cache)
let session = Session(cachedResponseHandler: cacher)

添加 EventMonitor(事件监视器)

EventMonitor 监听 Alamofire 内部各类事件,常用于日志打印、埋点。Session 初始化时传入数组。

swift

let monitor = ClosureEventMonitor()
monitor.requestDidCompleteTaskWithError = { (request, task, error) in
    debugPrint(request)
}
let session = Session(eventMonitors: [monitor])

操作全部活跃请求

该接口不常用,withAllRequests 可以批量操作当前所有正在运行的请求,执行在 rootQueue,逻辑要尽量简短。

swift

let session: Session = ...
session.withAllRequests { requests in
    requests.forEach { $0.suspend() }
}

一键取消全部请求,完成后回调:

swift

session.cancelAllRequests(completingOn: .main) {
    print("已取消全部请求")
}

注意:操作是异步执行,执行时部分请求可能已经完成或新建,不能保证操作集合完全符合预期。

基于已有 URLSession 创建 Session

除便捷构造器,也可以直接传入现成的 URLSession,但有诸多限制,优先使用便捷初始化:

  1. 不支持后台模式的 URLSession,会触发运行时错误。
  2. 必须手动创建 SessionDelegate,作为 URLSession 的 delegate,同时传给 Session。
  3. 必须自定义 OperationQueue 作为 delegateQueue,底层绑定串行 DispatchQueue,作为 Session 的 rootQueue。

swift

let rootQueue = DispatchQueue(label: "org.alamofire.customQueue")
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
queue.underlyingQueue = rootQueue
let delegate = SessionDelegate()
let configuration = URLSessionConfiguration.af.default
let urlSession = URLSession(
    configuration: configuration,
    delegate: delegate,
    delegateQueue: queue
)
let session = Session(session: urlSession, delegate: delegate, rootQueue: rootQueue)

请求 Requests

Alamofire 的请求分为 DataRequest、UploadRequest、DownloadRequest。DataRequest、DownloadRequest 继承自父类 Request;UploadRequest 继承 DataRequest。不要直接实例化 Request,全部由 Session 的 request 系列方法产出。

请求流水线 Request Pipeline

当创建一个 Request 子类之后,会经过一套流水线处理,成功请求完整流程:

  1. 将 method /headers/parameters 封装为内部 URLRequestConvertible;如果直接传入该类型,则直接复用。
  2. 调用 asURLRequest() 生成第一个 URLRequest,存入请求数组;如果创建时传入 RequestModifier,此时执行修改。
  3. 执行 Session / Request 上的 RequestAdapter / RequestInterceptor,修改 URLRequest,修改后的对象同样保存。
  4. Session 根据 URLRequest 创建 URLSessionTask,发起网络。
  5. Task 完成,收集 URLSessionTaskMetrics,执行校验器 Validator。
  6. 执行追加的响应回调,例如 responseDecodable。

流水线任意步骤都可能抛出错误,错误交给 Request。一旦发生错误,会尝试执行 RequestRetrier,如果选择重试,整个流水线重新跑一遍。

流水线各环节是否会报错:

  1. 参数封装:不会失败
  2. asURLRequest():可以抛出(参数编码、URL 校验失败)
  3. RequestAdapter:适配过程可以报错(如 token 缺失)
  4. 创建 URLSessionTask:不会失败
  5. URLSessionTask 执行:网络异常、取消等会产生错误
  6. 响应回调:解析数据可以抛出错误

Request 基类

Request 不区分请求类型,保存所有请求通用状态与能力。

State 状态枚举

swift

public enum State {
    case initialized   // 初始化完成
    case resumed       // 已启动
    case suspended     // 挂起暂停
    case cancelled     // 已取消
    case finished      // 请求全部完成
}
  • resume():启动 / 恢复网络请求。startRequestsImmediately=true 时添加回调会自动调用。
  • suspend():暂停请求。只有 DownloadRequest 有机会断点续传;其他请求恢复会重新发起。
  • cancel():取消请求,状态不可回退。error 属性被置为 AFError.explicitlyCancelled。

请求已经 finished 之后,如果再追加新的响应回调,会回到 resumed 状态重新执行网络请求。

Progress 进度

提供 uploadProgress、downloadProgress 闭包接口,建议在添加响应回调之前设置。

swift

AF.request(...)
    .uploadProgress { progress in
        print(progress)
    }
    .downloadProgress { progress in
        print(progress)
    }
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

上传进度依赖:上传 Data 长度 / 文件大小 / 手动设置的 Content‑Length。下载进度依赖:服务端返回 Content‑Length 响应头,否则进度一直是 0 直到完成。

处理重定向 Redirect

除 Session 全局 RedirectHandler,每个请求可以单独设置,会覆盖全局配置。

swift

let redirector = Redirector(behavior: .follow)
AF.request(...)
    .redirect(using: redirector)
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

一个请求只能设置一个 RedirectHandler,多次设置会运行时崩溃。

自定义缓存 Caching

单请求可以设置 CachedResponseHandler,覆盖 Session 全局配置。

swift

let cacher = ResponseCacher(behavior: .cache)
AF.request(...)
    .cacheResponse(using: cacher)
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

一个请求只能设置一个 CachedResponseHandler。

Credentials 凭证

用于处理服务器弹出的 HTTP 认证质询(401)。

swift

AF.request(...)
    .authenticate(username: "user@example.domain", password: "password")
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

⚠️ 仅针对服务器弹出认证框场景。如果接口每次请求都需要 Authorization 请求头,不要用这个,直接设置 header 或者 RequestAdapter。

也可以直接传入 URLCredential 对象:

swift

let credential = URLCredential(...)
AF.request(...)
    .authenticate(using: credential)
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }

Request 的生命周期对象

URLRequest

requests 数组保存该请求产生过的全部 URLRequest(原始的 + 经过适配器修改后的)。

注意:不包含 URLSessionTask 内部实际执行的请求。访问实际 task 看 .tasks 属性。

onURLRequestCreation 在每次生成 URLRequest 时回调,重试会多次触发;不能在闭包里修改 request 对象,修改请使用 RequestAdapter。

swift

AF.request(...)
    .onURLRequestCreation { request in
        print(request)
    }
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }
URLSessionTask

.tasks 数组保存该请求所有的 task,重试会新增 task。onURLSessionTaskCreation 在每次创建 task 回调;禁止在回调里操作 task 生命周期,只用来向外传递 task 对象。

swift

AF.request(...)
    .onURLSessionTaskCreation { task in
        print(task)
    }
    .responseDecodable(of: DecodableType.self) { response in
        debugPrint(response)
    }
HTTPURLResponse 响应回调

onHTTPResponse 在收到服务端响应头时触发,可以决定继续执行还是取消请求。

swift

AF.request(...)
    .onHTTPResponse { response, completionHandler in
        print(response)
        completionHandler(.allow) // .cancel 取消请求
    }

必须调用 completionHandler,否则请求会挂起直到超时。

Swift5.7 + 支持 async 闭包版本,也可以用异步序列迭代所有响应:

swift

let responses = AF.request(...).httpResponses()
for await response in responses {
    print(response)
}
URLSessionTaskMetrics 网络指标

每个 task 都会收集网络指标,response 对象上可以直接拿到。

watchOS <7 系统不支持收集 metrics。

swift

AF.request(...)
    .responseDecodable(of: DecodableType.self) { response in
        print(response.metrics)
    }

DataRequest

封装 URLSessionDataTask,下载数据读到内存。**超大文件不要使用,改用 DownloadRequest。**额外属性:data(收到的二进制数据)、convertible(创建请求的原始对象)。

Validation 校验

默认不会校验响应,必须手动调用 .validate()。

swift

public typealias Validation = (URLRequest?, HTTPURLResponse, Data?) -> Result<Void, Error>

默认校验:状态码 200‑299,Content‑Type 匹配 Accept。也可以自定义校验闭包。

swift

AF.request(...)
    .validate { request, response, data in
        // 自定义校验逻辑
        return .success(())
    }

DataStreamRequest

流式请求,URLSessionDataTask,持续接收数据流,不把全部数据存入内存。同样支持 validate,校验签名:

swift

public typealias Validation = (_ request: URLRequest?, _ response: HTTPURLResponse) -> Result<Void, Error>

UploadRequest

继承自 DataRequest,封装 URLSessionUploadTask,上传内存 Data、本地文件、InputStream。额外属性:fileManager、upload(封装上传源信息)。

DownloadRequest

封装 URLSessionDownloadTask,文件下载到磁盘。额外属性:

  • resumeData:取消时产出的数据,用于断点续传
  • fileURL:下载完成后本地文件地址

Cancellation 取消

支持普通 cancel,也可以取消同时获取断点续传数据:

swift

AF.download(...)
    .cancel { resumeData in
        // resumeData 用于恢复下载
    }

Validation

下载校验的闭包拿到的是文件 URL,而不是内存 Data。

swift

public typealias Validation = (_ request: URLRequest?, _ response: HTTPURLResponse, _ fileURL: URL?) -> Result<Void, Error>

RequestInterceptor 请求拦截器(适配 + 重试)

RequestInterceptor = RequestAdapter + RequestRetrier,可以全局 Session 设置,也可以单请求设置。典型场景:统一添加 token、token 过期自动刷新并重试请求。Alamofire 内置 RetryPolicy。

RequestAdapter 请求适配器

在网络真正发出之前修改 URLRequest,异步回调模式。

swift

func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void)

示例:统一添加 Bearer Token

swift

let accessToken: String
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
    var urlRequest = urlRequest
    urlRequest.headers.add(.authorization(bearerToken: accessToken))
    completion(.success(urlRequest))
}

新版本会使用带 RequestAdapterState 的重载,可以拿到 requestID,用于绑定自定义业务数据。

RequestRetrier 请求重试器

请求发生错误时决定是否重试。

swift

func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void)

RetryResult 枚举:

swift

public enum RetryResult {
    case retry                     // 立刻重试
    case retryWithDelay(TimeInterval) // 延迟后重试
    case doNotRetry                // 不重试
    case doNotRetryWithError(Error) // 不重试,返回指定错误
}

内置 RetryPolicy 实现指数退避重试逻辑,只对幂等请求重试。

组合多个 RequestInterceptor

使用 Interceptor 类型可以拼接多个适配器、重试器。适配器顺序执行,任意一个失败就终止;重试器按顺序执行。

swift

let adapter: RequestAdapter
let retrier: RequestRetrier
let interceptor: RequestInterceptor

let adapterAndRetrier = Interceptor(adapter: adapter, retrier: retrier)
let composite = Interceptor(interceptors: [adapterAndRetrier, interceptor])

AuthenticationInterceptor 认证拦截器

专门处理 OAuth 刷新 token 场景,处理并发请求排队等待刷新凭证的复杂逻辑。需要实现 Authenticator 协议,定义凭证模型 AuthenticationCredential。

示例 OAuth 凭证:

swift

struct OAuthCredential: AuthenticationCredential {
    let accessToken: String
    let refreshToken: String
    let userID: String
    let expiration: Date

    // 距离过期5分钟就需要刷新
    var requiresRefresh: Bool { Date(timeIntervalSinceNow: 60 * 5) > expiration }
}

实现 Authenticator:

swift

class OAuthAuthenticator: Authenticator {
    func apply(_ credential: OAuthCredential, to urlRequest: inout URLRequest) {
        urlRequest.headers.add(.authorization(bearerToken: credential.accessToken))
    }

    func refresh(_ credential: OAuthCredential,
                 for session: Session,
                 completion: @escaping (Result<OAuthCredential, Error>) -> Void) {
        // 在这里调用刷新token接口,回调返回新凭证
    }

    func didRequest(_ urlRequest: URLRequest,
                    with response: HTTPURLResponse,
                    failDueToAuthenticationError error: Error) -> Bool {
        // 判断本次失败是否属于鉴权失败,如 return response.statusCode == 401
        return false
    }

    func isRequest(_ urlRequest: URLRequest, authenticatedWith credential: OAuthCredential) -> Bool {
        // 判断请求是否已经使用该凭证
        return true
    }
}

使用:

swift

let credential = OAuthCredential(
    accessToken: "a0",
    refreshToken: "r0",
    userID: "u0",
    expiration: Date(timeIntervalSinceNow: 60 * 60)
)
let authenticator = OAuthAuthenticator()
let interceptor = AuthenticationInterceptor(authenticator: authenticator, credential: credential)

let session = Session()
let url = URL(string: "https://api.example.com/example/user")!
var urlRequest = URLRequest(url: url)
session.request(urlRequest, interceptor: interceptor)

DeflateRequestCompressor 请求体压缩

请求体很大时(大 JSON,图片不要压缩),使用 deflate 压缩请求体。

swift

session.request(..., interceptor: .deflateCompressor)

遇到已经存在 Content‑Encoding 头,可以配置冲突策略:

swift

public enum DuplicateHeaderBehavior {
    case error     // 默认,抛出错误
    case replace   // 覆盖原有头
    case skip      // 跳过压缩
}

也可以全局配置给 Session,通过闭包判断多大的数据才开启压缩:

swift

let compressor = DeflateRequestCompressor { bodyData in
    bodyData.count > 100 * 1024 // 大于100KB才压缩
}
let session = Session(..., interceptor: compressor)

Security 安全 TLS 证书校验

HTTPS 默认继承系统 URLSession 的证书校验,可以防止证书链非法,但无法防御中间人攻击。处理敏感数据建议开启证书锁定。

ServerTrustEvaluating 协议

自定义 TLS 评估逻辑,唯一方法:

swift

func evaluate(_ trust: SecTrust, forHost host: String) throws

内置评估器:

  • DefaultTrustEvaluator:系统默认校验,可控制是否校验主机名
  • RevocationTrustEvaluator:校验证书吊销状态(会产生网络开销)
  • PinnedCertificatesTrustEvaluator:证书锁定,支持自签名证书
  • PublicKeysTrustEvaluator:公钥锁定
  • CompositeTrustEvaluator:组合多个校验器,全部通过才算成功
  • DisabledTrustEvaluator:调试用!生产绝对禁止,关闭全部校验

ServerTrustManager

维护域名与评估器映射。

swift

let evaluators: [String: ServerTrustEvaluating] = [
    "cert.example.com": PinnedCertificatesTrustEvaluator(),
    "keys.example.com": PublicKeysTrustEvaluator()
]
let manager = ServerTrustManager(evaluators: evaluators)

不在映射表里的域名请求直接报错。如需通配域名,继承 ServerTrustManager,重写 serverTrustEvaluator(forHost:)。

App Transport Security ATS

使用自签名证书时,ATS 会覆盖 Alamofire 的校验逻辑,报 SSLHandshake (-9806)。需要修改 Info.plist。

本地开发使用自签名证书,添加:

xml

<dict>
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsLocalNetworking</key>
        <true/>
    </dict>
</dict>

自定义缓存与重定向

CachedResponseHandler 缓存处理器

控制 URLCache 缓存行为,仅对 DataTask(DataRequest / UploadRequest)生效。

swift

func dataTask(_ task: URLSessionDataTask,
              willCacheResponse response: CachedURLResponse,
              completion: @escaping (CachedURLResponse?) -> Void)

返回 nil = 不缓存;可以修改存储策略、Data、URLResponse。

内置实现 ResponseCacher:

swift

public enum Behavior {
    case cache
    case doNotCache
    case modify((URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)
}

RedirectHandler 重定向处理器

swift

func task(_ task: URLSessionTask,
          willBeRedirectedTo request: URLRequest,
          for response: HTTPURLResponse,
          completion: @escaping (URLRequest?) -> Void)