Alamofire 基础使用

目录

一、发起请求
  • 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-Typeapplication/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
    • BoolEncoding
      • numeric true as 1, false as 0. 默认
      • literal true as "true", false as "false"
    • DataEncoding
      • deferredToData nil
      • base64 data.base64EncodedString() 默认
      • custom((Data) throws -> String)
    • 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).
    • KeyEncoding
      • useDefaultKeys 原样式 默认
      • convertToSnakeCase oneTwoThree becomes one_two_three
      • convertToKebabCase oneTwoThree becomes one-two-three.
      • capitalized oneTwoThree becomes OneTwoThree
      • uppercased oneTwoThree becomes ONETWOTHREE.
      • lowercased oneTwoThree becomes onetwothree
      • custom((String) -> String)
    • SpaceEncoding
      • percentEscaped string.replacingOccurrences(of: " ", with: "%20")
      • plusReplaced string.replacingOccurrences(of: " ", with: "+")
    • alphabetizeKeyValuePairs key/value 按照字母排序,默认true

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

你可能感兴趣的:(Alamofire 基础使用)