基础用法和高级用法的区别:
- 基础用法:
-
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
创建自定义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() -> DataRequest
、AF.download() -> DownloadRequest
、AF.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)
发起请求