今天一起来研究下Alamofire
中请求参数相关内容。我们最熟悉的应该是使用字典来传递参数,像下面这样:
let parameters: [String: Any] = ["a": 1, "b": true]
AF.request("https://httpbin.org/get", parameters: parameters)
其实,我们还可以通过模型的方式传递。但前提是该模型遵循Encodable
协议,如下:
let parameters = struct { a: 1, "b": true }
AF.request("https://httpbin.org/get", parameters: parameters)
两种方式,对于调用者来说,基本上是无感的。下面就一起走进其背后的故事。
Alamofire支持的参数格式
字典类型
支持使用字典类型
创建请求的方法如下:
1、2是今天需要研究的;3是拦截器,具体参考这篇文章。
其实这里的Parameters
就是字典的别名:
public typealias Parameters = [String: Any]
该类型的编码器是ParameterEncoding
。它负责将Parameters
类型的参数合适的放入请求中。ParameterEncoding
是个协议:
/// 编码器,将参数编码至URLRequest中。
/// 注意:参数是字典类型。
public protocol ParameterEncoding {
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest
}
该协议的要求就一个方法,它接收URLRequestConvertible
和字典参数
,需要返回URLRequest
。该方法的职能很明确:负责使用传入的字典参数
加工URLRequest
并返回加工结果。能满足这个功能的都可以叫做ParameterEncoding
。
URLRequestConvertible
代表了可转换成URLRequest的类型
,可以从该类型中获取URLRequest
。
我们可以传递字典类型
参数,正是因为有了该协议的直接支持。该部分的类图如下:
对于URLEncoding
:
destination
控制将参数放在请求的什么位置。默认是根据请求方法自动判断,[.get, .head, .delete]
是将参数放在URL的query中,其他方法放在httpBody中。- 参数中有数组类型的话,如何编码通过
arrayEncoding
属性控制;同时boolEncoding
属性是控制如何编码Bool
类型的。
对于JSONEncoding
,它只会将参数放在请求的Body中。你要问为啥?那就是JSONEncoding
编码后的参数会变成Data
,只能通过body传输,并设置Content-Type
。
可编码类型
支持使用可编码类型
创建请求的方法如下:
其实这里的Parameters
是一个泛型。该类型参数对应的编码器为ParameterEncoder
,同样它也是协议:
/// 编码器,将参数编码至URLRequest中。
/// 注意:该方法为泛型方法,参数要求为可编码类型。
public protocol ParameterEncoder {
func encode<Parameters: Encodable>(_ parameters: Parameters?, into request: URLRequest) throws -> URLRequest
}
Alamofire
也默认实现了两种编码器。如下:
这里的设计和上一部分类似,不做细讲。
更进一步
对于两种参数格式,他们的处理流程大致如下:
我们以两种格式的参数为起点,以及两种格式的输出为终点,可以看到:
- 对于
JSON
类型的输出,由于系统内建的JSONEncoder
原本就是为了编码该类型而生,所以对于两种类型的输入,后面的支持者都是它。 - 对于
key=vale
格式的输出,系统没有此种功能的支持。所以这部分的实现都是由框架提供。具体的:- 字典类型的输入:直接在
URLEncoding
类中实现。 - 可编码类型的输入:背后的支持者为
URLEncodedFormEncoder
,由它实现具体的编码过程。
- 字典类型的输入:直接在
总结
今天我们了解到了Alamofire
中处理请求参数背后的故事。总结来说,就是支持Encodable
类型的参数。说到这里,其实字典也是支持Encodable
的,为什么这种类型单独领出来实现?(欢迎评论区讨论)