美文网首页
Alamofire-DataRequest流程解析

Alamofire-DataRequest流程解析

作者: SPIREJ | 来源:发表于2019-08-20 16:15 被阅读0次
    • 先来一张DataRequest的分析图
    SessionManager类dataRequest.jpeg

    Alamofire有四种RequestTask任务类型,如下

    enum RequestTask {
        case data(TaskConvertible?, URLSessionTask?)
        case download(TaskConvertible?, URLSessionTask?)
        case upload(TaskConvertible?, URLSessionTask?)
        case stream(TaskConvertible?, URLSessionTask?)
    }
    

    这里主要分析下DataRequest的流程

    首先使用Alamofirerequest非常简单

    SessionManager.default.request(urlStr, method: .get, parameters: nil)
                .response { (response) in
                    debugPrint(response)
            }
    
    • 来看一下SessionManagerrequest方法
    open func request(
        _ url: URLConvertible,
        method: HTTPMethod = .get,
        parameters: Parameters? = nil,
        encoding: ParameterEncoding = URLEncoding.default,
        headers: HTTPHeaders? = nil)
        -> DataRequest
    {
        var originalRequest: URLRequest?
    
        do {
            originalRequest = try URLRequest(url: url, method: method, headers: headers)
            let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
            return request(encodedURLRequest)
        } catch {
            return request(originalRequest, failedWith: error)
        }
    }
    
    ///------------分割线-------------///
    
    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)
        }
    }
    
    • 我们看到request方法由5个参数,除了url之外都有默认值或者为可选类型,参数分别为请求的url请求方式参数编码格式请求头

    • request方法返回DataRequest类型,这个后面细说

    • encode方法对请求的URL进行编码处理

    public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
        var urlRequest = try urlRequest.asURLRequest()
    
        guard let parameters = parameters else { return urlRequest }
    
        if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) {
            guard let url = urlRequest.url else {
                throw AFError.parameterEncodingFailed(reason: .missingURL)
            }
    
            if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty {
                let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters)
                urlComponents.percentEncodedQuery = percentEncodedQuery
                urlRequest.url = urlComponents.url
            }
        } else {
            if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
                urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
            }
    
            urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)
        }
    
        return urlRequest
    }
    

    (1)判断是否有参数
    (2) HTTPMethod判断
    GET: 百分比编码+拼接'&'
    query方法这里面有递归取URL中的参数,并且拼接上&符,注意joined方法最后一个元素不拼接&
    components.map { "\($0)=\($1)" }.joined(separator: "&")

    POST:
    (1)Content-Type
    (2)urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)

    • requestUrl 和 params处理完毕后
      delegate[task] = request
      这个地方就比较骚了
      request是面向开发者提供的请求,我们的请求是要执行具体事务的,这个具体事务就是--task
      let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
      具体怎么执行,request肯定不需要关心--交给delegate

    • dataTaskDelegate又是面向所有dataTask普通代理回调,但是我不知道是哪个task回来了?执行完毕?取消了?正在执行?这个时候我们的delegate很需要task

    • if startRequestsImmediately { request.resume() }开始执行外界request.resume

    open func resume() {
        guard let task = task else { delegate.queue.isSuspended = false ; return }
    
        if startTime == nil { startTime = CFAbsoluteTimeGetCurrent() }
    
        task.resume()
    
        NotificationCenter.default.post(
            name: Notification.Name.Task.DidResume,
            object: self,
            userInfo: [Notification.Key.Task: task]
        )
    }
    
    • 根据delegate[task] = request
    • 反向获取delegate.task
    • task.resume
    • 三次握手,代理回调

    总结

    上面就是Alamofire - DataRequest的基本流程,其他三种downloaduploadstream基本类似,只是在request初始化的时候根据RequestTask创建不同类型的taskDelegate

    • request初始化时首先保留一个originalRequest,然后对请求URL进行百分号编码,GET类型还需要&拼接参数,POST需要处理Content-TypeurlRequest.httpBody

    • 然后初始化originalTask.task
      return queue.sync { session.dataTask(with: urlRequest) }

    • 然后delegate[task] = request,注意这个地方很骚
      (1)这个delegateSessionDelegate
      (2)request是什么?
      let request = DataRequest(session: session, requestTask: .data(originalTask, task))

    就是把Request的代理移交给SessionDelegate,网络请求的代理回调到时候还是去SessionDelegate里面处理了具体的代理回调事务!

    • 最后if startRequestsImmediately { request.resume() }调用外界的request.resume(),执行task.resume(),任务开始,完美。

    相关文章

      网友评论

          本文标题:Alamofire-DataRequest流程解析

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