美文网首页
Alamofire之请求

Alamofire之请求

作者: 狂奔的胖蜗牛 | 来源:发表于2019-12-14 15:15 被阅读0次

1 原生网络请求与Alamofire区别

先来看看原生的网络请求是怎么样请求的:

let session = URLSession(configuration: .default)
let url = "https://ip.cn"
let request = URLRequest(url: URL(string: url)!)
let task = session.dataTask(with: request) { (data, response, error) in
    print(String(bytes: data!, encoding: .utf8)!)
}
task.resume()

再来看看Alamofire是怎么请求的:

Alamofire
    .request("https://ip.cn")
    .responseData { respons in
        print(String(bytes: respons.data!, encoding: .utf8)!)
    }

可以看出,Alamofire要简洁很多。然而我们要知道一件事情,Alamofire在请求网络的时候,依然是调用的系统原生的URLSession和URLRequest等,只是Alamofire给我们封装好了要如何调用。

2 揭开Alamofire.request()方法的面纱

2.1 查看Alamofire.request()的源码

@discardableResult  //如果不接收本方法的返回值,不会有提示
public func request(
    _ url: URLConvertible, //请求的url,符合URLConvertible协议的实例即可
    method: HTTPMethod = .get, //请求方法,默认GET请求
    parameters: Parameters? = nil, //请求参数
    encoding: ParameterEncoding = URLEncoding.default, //参数编码方式
    headers: HTTPHeaders? = nil) //请求头
    -> DataRequest // 请求实例
{
    return SessionManager.default.request(
        url,
        method: method,
        parameters: parameters,
        encoding: encoding,
        headers: headers
    )
}

通过源码,可以看出,request()方法内部,实际上是调用了SessionManager单例的request()方法,参数原封不动的传递了过去。

2.2查看SessionManager.default.request()的源码

    @discardableResult
    open func request(
        _ url: URLConvertible, //请求url
        method: HTTPMethod = .get, //请求方法
        parameters: Parameters? = nil, //请求参数
        encoding: ParameterEncoding = URLEncoding.default, //参数编码方式
        headers: HTTPHeaders? = nil) //请求头
        -> DataRequest //请求实例
    {
        var originalRequest: URLRequest?

        do {
            // 通过传递进来的url、method、headers创建出原生的请求
            originalRequest = try URLRequest(url: url, method: method, headers: headers)
            // 通过给定的编码方式编码参数获得编码过后的请求
            let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
            // 调用自身的request(_ urlRequest: URLRequestConvertible)方法,并返回
            return request(encodedURLRequest)
        } catch {
            return request(originalRequest, failedWith: error)
        }
    }

可以看出,本方法只是把传入的参数编码,然后生成原生的请求,传递给下一个方法进行处理。本方法还没有发送出请求。

2.3查看SessionManager.default.request(_ urlRequest: URLRequestConvertible)的源码

    @discardableResult
    open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
        var originalRequest: URLRequest?

        do {
            // 转换原生请求
            originalRequest = try urlRequest.asURLRequest()
            // 创建出请求任务的结构体
            let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
            // 创建出原生的请求任务
            let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
            // 创建出请求实例
            let request = DataRequest(session: session, requestTask: .data(originalTask, task))
            // 保存请求任务与请求实例的对应关系
            delegate[task] = request
            // 如果没有延时执行任务,则直接发出请求
            if startRequestsImmediately { request.resume() }
            // 返回请求实例
            return request
        } catch {
            return request(originalRequest, failedWith: error)
        }
    }

通过源码,可以看出,请求是在本方法中发送出去的。

3 Alamofire请求参数

@discardableResult
public func request(
    _ url: URLConvertible,
    method: HTTPMethod = .get,
    parameters: Parameters? = nil,
    encoding: ParameterEncoding = URLEncoding.default,
    headers: HTTPHeaders? = nil)
    -> DataRequest
{
    return SessionManager.default.request(
        url,
        method: method,
        parameters: parameters,
        encoding: encoding,
        headers: headers
    )
}

本方法中,涉及到Alamofire的内容有:

  • URLConvertible
public protocol URLConvertible {
    func asURL() throws -> URL
}

可以看到,这是一个协议,这也就是说,传入的url不一定是一个url字符串,只要是遵守了URLConvertible协议的实例就可以。Alamofire帮我们实现了很多,我们直接使用就可以了。如下:

extension String: URLConvertible {
    public func asURL() throws -> URL {
        guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) }
        return url
    }
}
extension URL: URLConvertible {
    public func asURL() throws -> URL { return self }
}
extension URLComponents: URLConvertible {
    public func asURL() throws -> URL {
        guard let url = url else { throw AFError.invalidURL(url: self) }
        return url
    }
}

所以,传入的url可以是String、URL、URLComponents三者之一。当然,我们是可以自定义的只要实现了协议即可。

  • HTTPMethod
public enum HTTPMethod: String {
    case options = "OPTIONS"
    case get     = "GET"
    case head    = "HEAD"
    case post    = "POST"
    case put     = "PUT"
    case patch   = "PATCH"
    case delete  = "DELETE"
    case trace   = "TRACE"
    case connect = "CONNECT"
}

这个没什么好说的。请求方法列表。默认是GET请求。

  • Parameters
public typealias Parameters = [String: Any]

可以看出,参数是字典,key必须是String。默认是nil。

  • ParameterEncoding
public protocol ParameterEncoding {
    func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest
}

参数编码方式传入的是遵循了ParameterEncoding协议,实现了编码参数方法的实例。默认值URLEncoding.default。

  • HTTPHeaders
public typealias HTTPHeaders = [String: String]

请求头也是字典,key和value都是String,默认值是nil。

至此,Alamofire的请求流程全部走了一遍。

4 总结

通过上面的流程,我们可以发现,Alamofire在很多地方是可以按照自己的需求去定制的。包括但不仅限于如下内容:

  • 1.可以自定义传入url的类型
  • 2.可以自定义传入参数编码的类型,也就可以自定义参数的编码方式
  • 3.可以自定义SessionManager
  • 4.可以设置任务是否是直接发出,默认是直接发出请求
  • 5.可以自定义请求转换方式

相关文章

网友评论

      本文标题:Alamofire之请求

      本文链接:https://www.haomeiwen.com/subject/cfkqpftx.html