目录
一、发起请求
- 1. 参数
- 2. ParameterEncoder 参数编码器
* 2.1 JSON参数编码器
* 2.2 Form参数编码器 - 3. HTTP Headers 请求头设置
- 4. 响应处理
二、下载文件
- 下载Data
- 下载到指定目录
- 下载进度
- 恢复下载
三、上传文件
- 上传 Data
- 上传文件
- 上传 Multipart Data
- 上传进度
Alamofire是基于Apple提供的 URL加载系统,核心是URLSession和URLSessionTask子类。 早期版本使用Alamofire.request(),5.0版本使用AF命名,AF引用Session.default
一、发起请求
简单示例:
AF.request("https://httpbin.org/get").response { response in
debugPrint(response)
}
两个发起请求的API
/// 1. 配置请求组成 URLRequest、本篇主要内容(基础用法)
open func request(_ convertible: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil) -> DataRequest
/// 2. 直接请求组装好的 URLRequest (高级用法)
open func request(_ urlRequest: URLRequestConvertible,
interceptor: RequestInterceptor? = nil) -> DataRequest
1. 参数
只要参数遵循Encodable
协议,那么最终ParameterEncoder
都会把Parameter
encode
成需要的数据类型
举个例子
struct Login: Encodable {
let email:String
let password:String
}
let login = Login(email: "aaa", password: "bbb")
AF.request("https://httpbin.org/post",
method: .post,
parameters: login,
encoder: JSONParameterEncoder.default)
.response { response in
debugPrint(response)
}
2. ParameterEncoder 参数编码器
参数编码器 最终决定了参数在请求中的存在的样式
我们通过参数编码器把参数编码成服务器需要的数据类型
Alamofire提供了2个两种编码器
JSONParameterEncoder
URLEncodedFormParameterEncoder
2.1 JSON参数编码器
JSONParameterEncoder
对应的 Content-Type
为 application/json
default
-
prettyPrinted
好看的格式打印 -
sortedKeys
key排序
/// 最终都是调用 encode 将参数转为 Data 保存在 httpBody 中
open func encode(_ value: T) throws -> Data where T : Encodable
let data = try encoder.encode(parameters)
request.httpBody = data
2.2 Form参数编码器
URLEncodedFormParameterEncoder
对应的 Content-Type
为
application/x-www-form-urlencoded; charset=utf-8
Form参数编码器只有一个默认的编码器default
- Destination 决定参数存放的位置
- methodDependent [.get, .head, .delete] 拼接URL ,默认使用此方式
- queryString 拼接URL
- httpBody
/// httpBody 调用encode 将参数转为 Data 保存在 httpBody 中
public func encode(_ value: Encodable) throws -> Data
/// 拼接URL获得新的URL
public func encode(_ value: Encodable) throws -> String {
...
URLEncodedFormEncoder.encode(value)
...
}
- URLEncodedFormEncoder 决定了参数中不同类型的key,value编码方式
- ArrayEncoding
- brackets
key[]
默认 - noBrackets
key
- brackets
- BoolEncoding
- numeric
true
as1
,false
as0
. 默认 - literal
true
as "true",false
as "false"
- numeric
- DataEncoding
- deferredToData
nil
- base64
data.base64EncodedString()
默认 - custom((Data) throws -> String)
- deferredToData
- DateEncoding
- deferredToDate
nil
默认 - secondsSince1970
String(date.timeIntervalSince1970)
- millisecondsSince1970
String(date.timeIntervalSince1970 * 1000.0)
- iso8601 ISO8601DateFormatter()
- formatted(DateFormatter)
formatter.string(from: date)
- custom((Date) throws -> String).
- deferredToDate
- KeyEncoding
- useDefaultKeys 原样式 默认
- convertToSnakeCase
oneTwoThree
becomesone_two_three
- convertToKebabCase
oneTwoThree
becomesone-two-three
. - capitalized
oneTwoThree
becomesOneTwoThree
- uppercased
oneTwoThree
becomesONETWOTHREE
. - lowercased
oneTwoThree
becomesonetwothree
- custom((String) -> String)
- SpaceEncoding
- percentEscaped
string.replacingOccurrences(of: " ", with: "%20")
- plusReplaced
string.replacingOccurrences(of: " ", with: "+")
- percentEscaped
- alphabetizeKeyValuePairs key/value 按照字母排序,默认true
- ArrayEncoding
3. HTTP Headers 请求头设置
提供3种初始化方式
/// 1. 无参构造
public init() {}
/// 通过以下方式添加值
func add(name: String, value: String)
func add(_ header: HTTPHeader)
/// 2. 通过 HTTPHeader 数组构造
public init(_ headers: [HTTPHeader])
let headers: HTTPHeaders = [
HTTPHeader(name: "Authorization", value: "Basic VXNlcm5hbWU6UGFzc3dvcmQ="),
HTTPHeader(name: "Accept", value: "application/json")
]
AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
debugPrint(response)
}
/// 3. 通过key/value 构造
public init(_ dictionary: [String: String])
let headers: HTTPHeaders = [
"Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=",
"Accept": "application/json"
]
AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
debugPrint(response)
}
4. 响应处理
Alamofire 提供了4种 Response
序列化工具
- DataResponseSerializer 解析为Data
// Response Handler - Unserialized Response
func response(queue: DispatchQueue = .main,
completionHandler: @escaping (AFDataResponse) -> Void) -> Self
// Response Data Handler - Serialized into Data
func responseData(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDataResponse) -> Void) -> Self
//示例
AF.request("https://httpbin.org/get").responseData { response in
debugPrint("Response: \(response)")
}
- StringResponseSerializer 解析为String
// Response String Handler - Serialized into String
func responseString(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
encoding: String.Encoding? = nil,
emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set = StringResponseSerializer.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDataResponse) -> Void) -> Self
//示例
AF.request("https://httpbin.org/get").responseString { response in
debugPrint("Response: \(response)")
}
- JSONResponseSerializer 解析为JSON
// Response JSON Handler - Serialized into Any Using JSONSerialization
func responseJSON(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set = JSONResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set = JSONResponseSerializer.defaultEmptyRequestMethods,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (AFDataResponse) -> Void) -> Self
//示例
AF.request("https://httpbin.org/get").responseJSON { response in
debugPrint("Response: \(response)")
}
- DecodableResponseSerializer 解析为指定类型<T: Decodable>
// Response Decodable Handler - Serialized into Decodable Type
func responseDecodable(of type: T.Type = T.self,
queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor,
decoder: DataDecoder = JSONDecoder(),
emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDataResponse) -> Void) -> Self
//示例
struct HTTPBinResponse: Decodable { let url: String }
AF.request("https://httpbin.org/get").responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint("Response: \(response)")
}
- DataResponseSerializerProtocol 使用自定义解析 Serializer: DataResponseSerializerProtocol
// Response Serializer Handler - Serialize using the passed Serializer
func response(queue: DispatchQueue = .main,
responseSerializer: Serializer,
completionHandler: @escaping (AFDataResponse) -> Void) -> Self
//示例 自定义解析为 Dictionary
public final class DictionaryResponseSerializer: ResponseSerializer {
public func serialize(request: URLRequest?,
response: HTTPURLResponse?,
data: Data?, error: Error?) throws -> Dictionary {
guard error == nil else { throw error! }
guard let data = data, !data.isEmpty else {
guard emptyResponseAllowed(forRequest: request, response: response) else {
throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
}
return [:]
}
do {
return try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.fragmentsAllowed) as! Dictionary
} catch {
throw AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error))
}
}
}
AF.request("https://httpbin.org/get").response(responseSerializer: DictionaryResponseSerializer()) { (response) in
switch response.result {
case .success(let bin):
debugPrint(bin)
case .failure(let error):
debugPrint(error)
}
}
二、下载文件
下载Data
AF.download("https://httpbin.org/image/png").responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
下载到指定目录
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
AF.download("https://httpbin.org/image/png", to: destination).response { response in
debugPrint(response)
if response.error == nil, let imagePath = response.fileURL?.path {
let image = UIImage(contentsOfFile: imagePath)
}
}
下载进度
AF.download("https://httpbin.org/image/png")
.downloadProgress { progress in
print("Download Progress: \(progress.fractionCompleted)")
}
.responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
恢复下载
var resumeData: Data!
let download = AF.download("https://httpbin.org/image/png").responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
// download.cancel(producingResumeData: true) // Makes resumeData available in response only.
download.cancel { data in
resumeData = data
}
AF.download(resumingWith: resumeData).responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
三、上传文件
上传 Data
let data = Data("data".utf8)
AF.upload(data, to: "https://httpbin.org/post").responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
上传文件
let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
AF.upload(fileURL, to: "https://httpbin.org/post").responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
上传 Multipart Data
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(Data("one".utf8), withName: "one")
multipartFormData.append(Data("two".utf8), withName: "two")
}, to: "https://httpbin.org/post")
.responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
上传进度
let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
AF.upload(fileURL, to: "https://httpbin.org/post")
.uploadProgress { progress in
print("Upload Progress: \(progress.fractionCompleted)")
}
.responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
最后封装了一个基于Moya&RXSwift&HandyJSON的网络库使用:PomeloNet