首先我们先看一下最简单的一个请求方法
public static func request(_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil) -> DataRequest
解读一下各个参数的意思:
url
我们可以看到url
的参数类型为URLConvertible
,点进去看一下会看到这是一个协议类型,定义如下
/// 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
可以对协议进行默认实现,Alamofire
中对String
和URL
两个类实现了该协议,并添加默认实现如下
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
请求类型,为一个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
请求参数及请求头
Parameters
我们可以看到实际上是一个别名public typealias Parameters = [String: Any]
HTTPHeaders
为一个结构体,持有一个[HTTPHeader]
的数组,我们可以通过HTTPHeader
的构造方法来创建header
参数。
HTTPHeaders
提供了一些默认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
对于这个参数,我的理解是在请求前及请求失败时候对request做统一处理的地方,首先我们看一下这个协议的定义
/// 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)
}
}
第一个方法,会在请求发起之前进行调用,比如我们可以在这个地方对urlRequest
进行一些请求参数及请求头的修改;
第二个方法则会在请求失败后进行调用。(有请求结果,例如response.statusCode = 400
之类的不会调用,因为这不算一次失败的请求,当然如果我们想让如此之类的请求也走该回调方便做统一处理,那么我们的请求方法需要这么写 Alamofile.request(url).validate().response
。 中间添加一个validate
)
我们看一下validate
具体做了什么:
首先Validation.swift
文件中有这么一个参数fileprivate var acceptableStatusCodes: Range<Int> { return 200..<300 }
,也就是200..<300
以外的statusCode
会走上边的retry(_request:for:dueTo:completion)
方法
我们看到Validation.swift
文件中对DataRequest
有如下扩展
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)
}
}
}
该方法,调用了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
中,当请求结束后,会对请求结果code进行一个比对,如下
func didCompleteTask(_ task: URLSessionTask, with error: Error?) {
self.error = self.error ?? error
// 如果我们请求时调用了 .validate() 则这个数组中便存在对应的 block,进行遍历,会把 200..<300 以外的code算为 Error,然后就会走 retry(_request:for:dueTo:completion) 这个方法
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() }
这句代码会走到该方法
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
}
这个方法中的let result = validation(self.request, response, self.data)
则会对code进行对比
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))
}
}
网友评论