学计算机的那个

不是我觉到、悟到,你给不了我,给了也拿不住;只有我觉到、悟到,才有可能做到,能做到的才是我的.

0%

Alamofire 5 使用

特性

  • 可链接的请求/响应函数
  • URL / JSON 参数编码
  • 上传文件 / Data / 流 / 多表单数据
  • 使用请求或者恢复数据下载文件
  • 使用 URLCredential 进行身份验证
  • HTTP 响应验证
  • 带有进度的上传和下载闭包
  • cURL 命令的输出
  • 动态调整和重试请求
  • TLS 证书和公钥固定
  • 网络可达性
  • 全面的单元和集成测试覆盖率

AF ,它是对 Session.default 的引用。

发起请求

1
2
3
AF.request("https://httpbin.org/get").response { response in
debugPrint(response)
}

这实际上是 Alamofire Session 类型上用于发出请求的两个顶层 APIs 的一种形式。它的完整定义如下:

1
2
3
4
5
6
7
8
open func request<Parameters: Encodable>(
_ convertible: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil
) -> DataRequest

此方法创建一个 DataRequest,同时允许组合来自各个组件(如 method 和 headers )的请求,同时还允许每个传入 RequestInterceptors 和 Encodable 参数。

这个 API 的第二个版本要简单得多:

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

此方法为遵循 Alamofire 的 URLRequestConvertible 协议的任何类型创建 DataRequest 。所有不同于前一版本的参数都封装在该值中,这会产生非常强大的抽象。

请求参数和参数编码器

Alamofire 支持将任何 Encodable 类型作为请求的参数。然后,这些参数通过遵循 ParameterEncoder 协议的类型传递,并添加到 URLRequest 中,然后通过网络发送。Alamofire 包含两种遵循 ParameterEncoder 的类型:JSONParameterEncoderURLEncodedFormParameterEncoder 。这些类型涵盖了现代服务使用的最常见的编码。

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Login: Encodable {
let email: String
let password: String
}

let login = Login(email: "test@test.test", password: "testPassword")

AF.request("https://httpbin.org/post",
method: .post,
parameters: login,
encoder: JSONParameterEncoder.default).response { response in
debugPrint(response)
}

URLEncodedFormParameterEncoder

URLEncodedFormParameterEncoder 将值编码为 URL 编码字符串,以将其设置为或附加到任何现有 URL 查询字符串,或设置为请求的 HTTP body。通过设置编码的目的地,可以控制编码字符串的设置位置。URLEncodedFormParameterEncoder.Destination 枚举有三种情况:

  1. .methodDependent - 对于 .get、.head、.delete 请求,它会将已编码查询字符串应用到现有的查询字符串中;对于其他类型的请求,会将其设置为 HTTP body
  2. .queryString - 将编码字符串设置或追加到请求的 URL 中。
  3. .httpBody - 将编码字符串设置为 URLRequest 的 HTTP body。

如果尚未设置 Content-Type,那么会把具有 HTTP body 的已编码请求的 HTTP header 设置为 application/x-www-form-urlencoded; charset=utf-8

在内部,URLEncodedFormParameterEncoder 使用 URLEncodedFormEncoderEncodable 类型编码为 URL 编码形式的 String。此编码器可用于自定义各种类型的编码,包括使用 ArrayEncodingArray、使用 BoolEncodingBool、使用 DataEncodingData、使用 DateEncodingDate、使用 KeyEncodingkeys 以及使用 SpaceEncoding 的空格。

使用 URL 编码参数的 GET 请求

1
2
3
4
5
6
7
8
let parameters = ["foo": "bar"]

// 下面三种方法都是等价的
AF.request("https://httpbin.org/get", parameters: parameters) // encoding defaults to `URLEncoding.default`
AF.request("https://httpbin.org/get", parameters: parameters, encoder: URLEncodedFormParameterEncoder.default)
AF.request("https://httpbin.org/get", parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .methodDependent))

// https://httpbin.org/get?foo=bar

使用 URL 编码参数的 POST 请求

1
2
3
4
5
6
7
8
9
10
11
12
let parameters: [String: [String]] = [
"foo": ["bar"],
"baz": ["a", "b"],
"qux": ["x", "y", "z"]
]

// 下面三种方法都是等价的
AF.request("https://httpbin.org/post", method: .post, parameters: parameters)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .httpBody))

// HTTP body: "qux[]=x&qux[]=y&qux[]=z&baz[]=a&baz[]=b&foo[]=bar"

JSONParameterEncoder

JSONParameterEncoder 使用 Swift 的 JSONEncoderEncodable 值进行编码,并将结果设置为 URLRequesthttpBody。如果 Content-Type 尚未设置,则将其设置为 application/json

JSON 编码参数的 POST 请求

1
2
3
4
5
6
7
8
9
10
11
let parameters: [String: [String]] = [
"foo": ["bar"],
"baz": ["a", "b"],
"qux": ["x", "y", "z"]
]

AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.default)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.prettyPrinted)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.sortedKeys)

// HTTP body: {"baz":["a","b"],"foo":["bar"],"qux":["x","y","z"]}

手动对URLRequest进行参数编码

ParameterEncoder APIs 也可以在 Alamofire 之外使用,方法是直接在URLRequest 中编码参数

1
2
3
4
5
let url = URL(string: "https://httpbin.org/get")!
var urlRequest = URLRequest(url: url)

let parameters = ["foo": "bar"]
let encodedURLRequest = try URLEncodedFormParameterEncoder.default.encode(parameters, into: urlRequest)

HTTP Headers

Alamofire 包含自己的 HTTPHeaders 类型,这是一种顺序保持且不区分大小写的 HTTP header name/value 对的表示。HTTPHeader 类型封装单个 name/value 对,并为常用的 headers 提供各种静态值。

向 Request 添加自定义 HTTPHeaders 就像向 request 方法传递值一样简单:

1
2
3
4
5
6
7
8
let headers: HTTPHeaders = [
"Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=",
"Accept": "application/json"
]

AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
debugPrint(response)
}

HTTPHeaders 也可以由 HTTPHeader 数组构造:

1
2
3
4
5
6
7
8
let headers: HTTPHeaders = [
.authorization(username: "Username", password: "Password"),
.accept("application/json")
]

AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
debugPrint(response)
}

对于不会变的 HTTP headers,建议在 URLSessionConfiguration 上设置它们,以便让它们自动应用于底层 URLSession 创建的任何 URLSessionTask。

默认的 Alamofire Session 为每个 Request 提供一组默认的 headers。其中包括:

  • Accept-Encoding,默认为 br;q=1.0, gzip;q=0.8, deflate;q=0.6,根据 RFC 7230 §4.2.3。
  • Accept-Language,默认为系统中最多 6 种首选语言,格式为 en;q=1.0,根据 RFC 7231 §5.3.5。
  • User-Agent,其中包含有关当前应用程序的版本信息。例如:iOS Example/1.0 (com.alamofire.iOS-Example; build:1; iOS 13.0.0) Alamofire/5.0.0,根据 RFC 7231 §5.5.3。

如果需要自定义这些 headers,则应创建自定义 URLSessionConfiguration,更新 defaultHTTPHeaders 属性,并将配置应用于新 Session 实例。使用URLSessionConfiguration.af.default 来自定义配置,会保留 Alamofire 的默认 headers。

响应验证

如果响应具有不可接受的状态代码或 MIME 类型,则在响应处理程序之前调用 validate() 将导致生成错误

自动验证

validate() API 自动验证状态代码是否在 200..<300 范围内,以及响应的 Content-Type header 是否与请求的 Accept 匹配(如果有提供)。

1
2
3
AF.request("https://httpbin.org/get").validate().responseJSON { response in
debugPrint(response)
}

手动验证

1
2
3
4
5
6
7
8
9
10
11
AF.request("https://httpbin.org/get")
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseData { response in
switch response.result {
case .success:
print("Validation Successful")
case let .failure(error):
print(error)
}
}

响应处理

Alamofire 的 DataRequestDownloadRequest 都有相应的响应类型:DataResponse<Success, Failure: Error>DownloadResponse<Success, Failure: Error>。这两个类型都由两个泛型组成:序列化类型和错误类型。默认情况下,所有响应值都将生成 AFError 错误类型(DataResponse<Success, AFError>)。Alamofire 在其公共 API 中使用了更简单的 AFDataResponse<Success>AFDownloadResponse<Success>,它们总是有 AFError 错误类型。UploadRequest 是 DataRequest 的一个子类,使用相同的 DataResponse 类型。

处理在 Alamofire 中发出的 DataRequest 或 UploadRequest 的 DataResponse 涉及到链接 response handler,例如 responseJSON 链接到 DataRequest:

1
2
3
AF.request("https://httpbin.org/get").responseJSON { response in
debugPrint(response)
}

在上面的示例中,responseJSON handler 被添加到 DataRequest 中,以便在 DataRequest 完成后执行。传递给 handler 闭包的参数是从响应属性来的 JSONResponseSerializer 生成的 AFDataResponse<Any> 值。

此闭包并不阻塞执行以等待服务器的响应,而是作为回调添加,以便在收到响应后处理该响应。请求的结果仅在响应闭包的范围内可用。任何依赖于从服务器接收到的响应或数据的执行都必须在响应闭包中完成。

默认情况下,Alamofire 包含六个不同的数据响应 handlers,包括:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

// Response Handler - 未序列化的 Response
func response(
queue: DispatchQueue = .main,
completionHandler: @escaping (AFDataResponse<Data?>) -> Void
) -> Self

// Response Serializer Handler - Serialize using the passed Serializer
func response<Serializer: DataResponseSerializerProtocol>(
queue: DispatchQueue = .main,
responseSerializer: Serializer,
completionHandler: @escaping (AFDataResponse<Serializer.SerializedObject>) -> Void
) -> Self

// Response Data Handler - Serialized into Data
func responseData(
queue: DispatchQueue = .main,
completionHandler: @escaping (AFDataResponse<Data>) -> Void
) -> Self

// Response String Handler - Serialized into String
func responseString(
queue: DispatchQueue = .main,
encoding: String.Encoding? = nil,
completionHandler: @escaping (AFDataResponse<String>) -> Void
) -> Self

// Response JSON Handler - Serialized into Any Using JSONSerialization
func responseJSON(
queue: DispatchQueue = .main,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (AFDataResponse<Any>) -> Void
) -> Self

// Response Decodable Handler - Serialized into Decodable Type
func responseDecodable<T: Decodable>(
of type: T.Type = T.self,
queue: DispatchQueue = .main,
decoder: DataDecoder = JSONDecoder(),
completionHandler: @escaping (AFDataResponse<T>) -> Void
) -> Self

没有一个响应 handlers 对从服务器返回的 HTTPURLResponse 执行任何验证。

例如,400..<500 和 500..<600 范围内的响应状态代码不会自动触发错误。Alamofire 使用响应验证链接来实现这一点。

参考

Alamofire 5 的使用 - 基本用法