首先我們先看一下最簡單的一個(gè)請(qǐng)求方法
public static func request(_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil) -> DataRequest
解讀一下各個(gè)參數(shù)的意思:
url
我們可以看到url
的參數(shù)類型為URLConvertible
,點(diǎn)進(jìn)去看一下會(huì)看到這是一個(gè)協(xié)議類型求摇,定義如下
/// Types adopting the `URLConvertible` protocol can be used to construct `URL`s, which can then be used to construct
/// `URLRequests`.
public protocol URLConvertible {
/// Returns a `URL` from the conforming instance or throws.
///
/// - Returns: The `URL` created from the instance.
/// - Throws: Any error thrown while creating the `URL`.
func asURL() throws -> URL
}
而swift
中通過extension
可以對(duì)協(xié)議進(jìn)行默認(rèn)實(shí)現(xiàn),Alamofire
中對(duì)String
和URL
兩個(gè)類實(shí)現(xiàn)了該協(xié)議,并添加默認(rèn)實(shí)現(xiàn)如下
extension String: URLConvertible {
/// Returns a `URL` if `self` can be used to initialize a `URL` instance, otherwise throws.
///
/// - Returns: The `URL` initialized with `self`.
/// - Throws: An `AFError.invalidURL` instance.
public func asURL() throws -> URL {
guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) }
return url
}
}
extension URL: URLConvertible {
/// Returns `self`.
public func asURL() throws -> URL { return self }
}
method
請(qǐng)求類型打月,為一個(gè)enum
public enum HTTPMethod: String {
/// `CONNECT` method.
case connect = "CONNECT"
/// `DELETE` method.
case delete = "DELETE"
/// `GET` method.
case get = "GET"
/// `HEAD` method.
case head = "HEAD"
/// `OPTIONS` method.
case options = "OPTIONS"
/// `PATCH` method.
case patch = "PATCH"
/// `POST` method.
case post = "POST"
/// `PUT` method.
case put = "PUT"
/// `TRACE` method.
case trace = "TRACE"
}
parameters 及 headers
請(qǐng)求參數(shù)及請(qǐng)求頭
Parameters
我們可以看到實(shí)際上是一個(gè)別名public typealias Parameters = [String: Any]
HTTPHeaders
為一個(gè)結(jié)構(gòu)體辞嗡,持有一個(gè)[HTTPHeader]
的數(shù)組不狮,我們可以通過HTTPHeader
的構(gòu)造方法來創(chuàng)建header
參數(shù)欣除。
HTTPHeaders
提供了一些默認(rèn)header
public extension HTTPHeaders {
/// The default set of `HTTPHeaders` used by Alamofire. Includes `Accept-Encoding`, `Accept-Language`, and
/// `User-Agent`.
static let `default`: HTTPHeaders = [.defaultAcceptEncoding,
.defaultAcceptLanguage,
.defaultUserAgent]
}
interceptor
對(duì)于這個(gè)參數(shù),我的理解是在請(qǐng)求前及請(qǐng)求失敗時(shí)候?qū)equest做統(tǒng)一處理的地方潭袱,首先我們看一下這個(gè)協(xié)議的定義
/// Type that provides both `RequestAdapter` and `RequestRetrier` functionality.
public protocol RequestInterceptor: RequestAdapter, RequestRetrier {}
extension RequestInterceptor {
public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (AFResult<URLRequest>) -> Void) {
completion(.success(urlRequest))
}
public func retry(
_ request: Request,
for session: Session,
dueTo error: Error,
completion: @escaping (RetryResult) -> Void)
{
completion(.doNotRetry)
}
}
第一個(gè)方法柱嫌,會(huì)在請(qǐng)求發(fā)起之前進(jìn)行調(diào)用,比如我們可以在這個(gè)地方對(duì)urlRequest
進(jìn)行一些請(qǐng)求參數(shù)及請(qǐng)求頭的修改屯换;
第二個(gè)方法則會(huì)在請(qǐng)求失敗后進(jìn)行調(diào)用慎式。(有請(qǐng)求結(jié)果,例如response.statusCode = 400
之類的不會(huì)調(diào)用趟径,因?yàn)檫@不算一次失敗的請(qǐng)求,當(dāng)然如果我們想讓如此之類的請(qǐng)求也走該回調(diào)方便做統(tǒng)一處理癣防,那么我們的請(qǐng)求方法需要這么寫 Alamofile.request(url).validate().response
蜗巧。 中間添加一個(gè)validate
)
我們看一下validate
具體做了什么:
首先Validation.swift
文件中有這么一個(gè)參數(shù)fileprivate var acceptableStatusCodes: Range<Int> { return 200..<300 }
,也就是200..<300
以外的statusCode
會(huì)走上邊的retry(_request:for:dueTo:completion)
方法
我們看到Validation.swift
文件中對(duì)DataRequest
有如下擴(kuò)展
extension DataRequest {
/// Validates that the response has a status code in the specified sequence.
///
/// If validation fails, subsequent calls to response handlers will have an associated error.
///
/// - parameter range: The range of acceptable status codes.
///
/// - returns: The request.
@discardableResult
public func validate<S: Sequence>(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int {
return validate { [unowned self] _, response, _ in
return self.validate(statusCode: acceptableStatusCodes, response: response)
}
}
}
該方法蕾盯,調(diào)用了Request.swift
文件中的方法
@discardableResult
public func validate(_ validation: @escaping Validation) -> Self {
let validator: () -> Void = { [unowned self] in
guard self.error == nil, let response = self.response else { return }
let result = validation(self.request, response, self.data)
if case .failure(let error) = result { self.error = error }
self.eventMonitor?.request(self,
didValidateRequest: self.request,
response: response,
data: self.data,
withResult: result)
}
protectedValidators.append(validator)
return self
}
該方法把block保存在protectedValidators
中幕屹,當(dāng)請(qǐng)求結(jié)束后,會(huì)對(duì)請(qǐng)求結(jié)果code進(jìn)行一個(gè)比對(duì),如下
func didCompleteTask(_ task: URLSessionTask, with error: Error?) {
self.error = self.error ?? error
// 如果我們請(qǐng)求時(shí)調(diào)用了 .validate() 則這個(gè)數(shù)組中便存在對(duì)應(yīng)的 block望拖,進(jìn)行遍歷渺尘,會(huì)把 200..<300 以外的code算為 Error,然后就會(huì)走 retry(_request:for:dueTo:completion) 這個(gè)方法
protectedValidators.directValue.forEach { $0() }
eventMonitor?.request(self, didCompleteTask: task, with: error)
retryOrFinish(error: self.error)
}
func retryOrFinish(error: Error?) {
guard let error = error, let delegate = delegate else { finish(); return }
delegate.retryResult(for: self, dueTo: error) { retryResult in
switch retryResult {
case .doNotRetry, .doNotRetryWithError:
self.finish(error: retryResult.error)
case .retry, .retryWithDelay:
delegate.retryRequest(self, withDelay: retryResult.delay)
}
}
}
上面的protectedValidators.directValue.forEach { $0() }
這句代碼會(huì)走到該方法
public func validate(_ validation: @escaping Validation) -> Self {
let validator: () -> Void = { [unowned self] in
guard self.error == nil, let response = self.response else { return }
let result = validation(self.request, response, self.data)
if case .failure(let error) = result { self.error = error }
self.eventMonitor?.request(self,
didValidateRequest: self.request,
response: response,
data: self.data,
withResult: result)
}
protectedValidators.append(validator)
return self
}
這個(gè)方法中的let result = validation(self.request, response, self.data)
則會(huì)對(duì)code進(jìn)行對(duì)比
fileprivate func validate<S: Sequence>(
statusCode acceptableStatusCodes: S,
response: HTTPURLResponse)
-> ValidationResult
where S.Iterator.Element == Int
{
if acceptableStatusCodes.contains(response.statusCode) {
return .success(Void())
} else {
let reason: ErrorReason = .unacceptableStatusCode(code: response.statusCode)
return .failure(AFError.responseValidationFailed(reason: reason))
}
}