美文网首页
Alamofire框架解读(一)--关于URLSession

Alamofire框架解读(一)--关于URLSession

作者: JackLin11 | 来源:发表于2019-08-19 10:58 被阅读0次

    [toc]

    1 URLSession的使用

    1.1 发起一个简单的请求

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if error == nil {
            print("请求成功\(String(describing: response))" )
        }
    }.resume()
    

    步骤:
    1.创建URLSession实例。
    2.创建并添加URLSessionTask实例。
    3.resume()方法开启URLSessionTask。

    1.2 复杂一点的用法

    // 创建URLSessionDelegate并实现代理方法。
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        // ...
    }
    
     func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        // ...
     }
    
    
    func tesURLSession() {
        // 1.创建URLSessionConfiguration
        let configurationEphemeral = URLSessionConfiguration.ephemeral
        // 3.根据configure、delegate、delegate执行的队列创建URLSession实例
        let session = URLSession.init(configuration: configurationEphemeral, delegate: self, delegateQueue: OperationQueue.main)
        // 4.创建URLSessionDelegate并实现代理方法。 
        // 5.resume()方法开启URLSessionTask
        session.downloadTask(with: url).resume();
    }
    
    

    步骤:
    1.创建URLSessionConfiguration。
    2.创建URLSessionDelegate。
    3.根据configure、delegate、delegate执行的队列创建URLSession实例。
    4.创建并添加URLSessionTask实例。
    5.resume()方法开启URLSessionTask。

    2 从URLConnection到URLSession

    2.1 Connect与Session

    先看看官方文档对于URLSession的第一句描述。

    NSURLSession is a replacement API for NSURLConnection。
    

    也就是说Apple推出URLSession就是用来替换NSURLConnection。那么为什么要搞出来个URLSession去代替NSURLConnection而不是在NSURLConnection上去迭代?
    我们先理解一下session和connect的直观含义,前者是会话、后者是连接,做过数据库、通信协议相关开发和研究工作的小伙伴都能理解这二者的区别。

    我们先看看数据库访问中二者的区别(以下摘自 Oracle 9i &10g 编程艺术):

    连接(connection):连接是从客户到Oracle 实例的一条物理路径。连接可以在网络上建立,或者通过IPC机制建立。通常会在客户进程与一个专用服务器或一个调度器之间建立连接。
    会话(session):会话是实例中存在的一个逻辑实体。这就是你的会话状态(session state),也就是表示特定会话的一组内存中的数据结构.提到"数据库连接"时,大多数人首先想到的就是“会话”。你要在服务器中的会话上执行SQL、提交事务和运行存储过程。

    一般来说,会话=连接+状态,一个连接可以提供给多个会话,而一个会话也有可能利用多个连接。
    有小伙伴会说,http是无状态的,所以只有http连接一说,没有http会话一说。确实,早期http是无状态的,后来为了提高http工作的效率,加入了cookie/session机制,cookie/session保存http的状态,http会话由此诞生。

    据此,Apple将他们设备里的一个http请求当做一个http会话,或者说是一个URLSession是没有任务问题的。

    2.2 从URLConnection到URLSession的转变与http2.0是不是有联系

    从URLConnection到URLSession的转变与http2.0是不是有联系呢?我们先看看两个时间点:
    ios7.0发布时间 2013.09
    http2.0草案测试版本发布时间 2013.08

    再看看HTTP2.0相较于http1.0主要做了什么

    协议的目标:
    异步多路复用
    头部压缩
    请求/响应管线化

    重点看看这个异步多路复用,不了解的小伙伴可以去这篇博客了解一下,浅析HTTP/2的多路复用

    我这里简单的说一下,http1.1搞出来个长连接,主要是为了解决http1.0发起一个http请求要重新通过tcp握手协议建立tcp通道的资源浪费问题。但是http1.1又有个问题:串行的文件传输效率低、服务器连接数过多压力过大问题。于是在http2.0就搞出了个多路复用。细节小伙伴可以去看一下上面的文章和其他的资料。

    回到我们的问题:从URLConnection到URLSession的转变与http2.0是不是有联系呢?
    以前我们对于一个http请求,就说是一个connection显然是合适的。但是在http2.0中,浏览器或者客户端对一个域名发起的所有http请求都用的是同一个http连接,也就是说肯定不会创建连接,那么发起一个请求叫URLConnection显示是不合适的。
    那么http2.0发起一个http请求用什么合适呢?Apple选择的是建立会话Session,发起一个http请求就是发起一个会话,完成一个或多个任务。

    3 URLSession-Configuration

    3.1 Configrantion是什么

    翻阅文档看看。(以下引文均载自官方文档)

    Overview
    An URLSessionConfiguration object defines the behavior and policies to use when uploading and downloading data using an URLSession object. When uploading or downloading data, creating a configuration object is always the first step you must take. You use this object to configure the timeout values, caching policies, connection requirements, and other types of information that you intend to use with your URLSession object.

    It is important to configure your URLSessionConfiguration object appropriately before using it to initialize a session object. Session objects make a copy of the configuration settings you provide and use those settings to configure the session. Once configured, the session object ignores any changes you make to the URLSessionConfiguration object. If you need to modify your transfer policies, you must update the session configuration object and use it to create a new URLSession object.

    Overview中关于URLConfigrantion的描述有以下几个重要信息:
    1、URLSessionConfiguration对象定义了使用URLSession对象上传和下载数据时使用的行为和策略。
    2、用URLSessionConfiguration对象来为URLSession对象配置超时值、缓存策略、连接需求和其他类型的信息。
    3、创建URLSession必须创建配置URLSessionConfiguration。并且一旦创建不可修改,如果想更改只能重新创建一个URLSession。

    Note
    In some cases, the policies defined in this configuration may be overridden by policies specified by an NSURLRequest object provided for a task. Any policy specified on the request object is respected unless the session’s policy is more restrictive. For example, if the session configuration specifies that cellular networking should not be allowed, the NSURLRequest object cannot request cellular networking.

    该注意点提到任务中的NSURLRequest可能会覆盖配置中定义的策略。某些策略是Configuration指定的,不能被NSURLRequest覆盖。例如,如果会话配置指定不允许蜂窝网络,则NSURLRequest对象无法请求蜂窝网络。

    关于Types of Session Configurations

    The behavior and capabilities of a URL session are largely determined by the kind of configuration used to create the session.

    The singleton shared session (which has no configuration object) is for basic requests. It’s not as customizable as sessions that you create, but it serves as a good starting point if you have very limited requirements. You access this session by calling the shared class method. See that method’s discussion for more information about its limitations.

    Default sessions behave much like the shared session (unless you customize them further), but let you obtain data incrementally using a delegate. You can create a default session configuration by calling the default method on the URLSessionConfiguration class.

    Ephemeral sessions are similar to default sessions, but they don’t write caches, cookies, or credentials to disk. You can create an ephemeral session configuration by calling the ephemeral method on the URLSessionConfiguration class.

    Background sessions let you perform uploads and downloads of content in the background while your app isn’t running. You can create a background session configuration by calling the backgroundSessionConfiguration(_:) method on the URLSessionConfiguration class.

    Configurations主要有三种模式:

    1. Default sessions:这是一个默认模式,其他相关配置会取默认项。它会将缓存、cookie或者凭据写入磁盘。它有一个磁盘缓存。
    2. Ephemeral sessions:临时会话模式。和Default模式类似。只是没有磁盘缓存,不会将缓存、cookie或凭据写入磁盘。
    3. Background sessions:后台会话允许您在应用程序不运行时在后台执行内容的上载和下载。可以通过调用URLSessionConfiguration类上的backgroundSessionConfiguration(_:)方法来创建后台会话配置。 这里有些问题可以通过调用URLSessionConfiguration类上的backgroundSessionConfiguration(_:) 已经废弃了,现在用background(withIdentifier: String) 。

    在1.1中使用的URLSession单例,它的Configurations是default模式。

    测试Default、和Ephemeral模式
    // default - 默认,有持久缓存器,保存
    let configurationDefault = URLSessionConfiguration.default
    
    // ephemeral - 短暂的,无持久缓存器,
    let configurationEphemeral = URLSessionConfiguration.ephemeral
    
    print("沙盒大小:\(String(describing: configurationDefault.urlCache?.diskCapacity))")
    print("内存大小:\(String(describing: configurationDefault.urlCache?.memoryCapacity))")
    
    print("沙盒大小:\(String(describing: configurationEphemeral.urlCache?.diskCapacity))")
    print("内存大小:\(String(describing: configurationEphemeral.urlCache?.memoryCapacity))")
    
    // 打印结果
    沙盒大小:Optional(10000000)
    内存大小:Optional(512000)
    沙盒大小:Optional(0)
    内存大小:Optional(512000)
    

    打印结果可以看出ephemeral是没有磁盘缓存的。小伙伴们也可以去模拟器的tmp文件夹下观察相关缓存的变换和区别。

    创建一个后台下载
    let date:Date = Date.init(timeIntervalSinceNow: 0)
    let timeInterval:TimeInterval = date.timeIntervalSince1970
    // 后台下载,这里我们以时间戳作为标识
    let configurationBackground = URLSessionConfiguration.background(withIdentifier: "\(timeInterval)")
    // 创建session
    let session = URLSession.init(configuration: configurationBackground, delegate: self, delegateQueue: OperationQueue.main)
    // resume启动线程
    session.downloadTask(with: url).resume();
    
    // 配置delegate略
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        print("didFinishDownloadingTo")
    }
    
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { 
        print("didFinishDownloadingTo")
    }
    
    

    有两点需要注意:

    1. 要想后台模式生效必须在Appdelegate中实现application:handleEventsForBackgroundURLSession:completionHandler:方法。
    2. 后台模式下并不是所有的URLSession代理方法都会回调。
      比如上面的下载模式下func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)方法和optional func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64)会回调但是optional func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)则不会回调。
    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
            print("handleEventsForBackgroundURLSession")
    }
    

    3.2 URLSessionConfiguration属性

    常规属性

    1. identifier:配置对象的后台标识符。

    2. httpAdditionalHeaders:与请求一起发送的附加头文件的字典。
      不要对以下头进行更改:Authorization、Connection、Host、Proxy-Authenticate、Proxy-Authorization、WWW-Authenticate。
      Content-Length这个头字段会自动计算出来,不需要我们自己设置。
      这个配置的值如果和URLRequest对象里设置的header有相同的key,则会被后者覆盖。

    3. networkServiceType:网络请求类型。默认是NSURLRequest.NetworkServiceType.default。
      通过提供准确的信息,您可以提高系统优化平衡电池寿命、性能和其他注意事项的能力。大多数情况下用NSURLRequest.NetworkServiceType.default。类型有default、voip、video、background、voice、callSignaling(请求时呼叫信号)、responsiveData(用户迫切等待的数据)。
      设置网络请求类型究竟有多大提升呢?以后再研究。

    4. allowsCellularAccess:确定是否通过蜂窝网络进行连接。默认是ture。

    5. timeoutIntervalForRequest:等待附加数据时使用的超时时间间隔。默认60s。
      这个超时是一次TCP请求发起到接收的超时时间设置,如果超过该时间则发起超时重传机制,要求对方再传一次,上一个超时数据到来也不会接收。一般不会修改该值。

    6. timeoutIntervalForResource:允许资源请求占用的最大时间。默认是7天。
      一般性数据请求会设置该值(比如请求用户信息等需要停留在页面等待数据要设置比较小的值),而后台上传或者下载其他任务要根据实际情况慎重选择该值。如果超时,任务会废弃并启动超时处理机制,超时处理需要我们自己来定义处理(一般三方网络框架会友好的暴露该超时回调)。

    7. sharedContainerIdentifier:后台URL会话中的文件下载到的共享容器的标识符。一般不设置该值。
      关于应用扩展的的内容和共享容器设置可以参看这篇官方文档
      以后有时间再详述ios应用扩展相关内容。

    8. waitsForConnectivity:一个布尔值指示会话是否应等等连接变为可用或者立即失败。默认是false。
      对于一些需要耗时的任务,比如wifi模式上传一个小视频的后台任务,蜂窝网络不予执行,我们为了使用户恢复网络后继续上传一般会将这个值设置为YES。
      需要注意的是,这个属性ios11及以上才支持。
      对于网络丢失的处理,官方给出了相关的文档

    设置Cookie策略

    1. httpCookieAcceptPolicy:决定何时应该接受Cookie的策略性常数。默认值是HTTPCookie.AcceptPolicy.onlyFromMainDocumentDomain。
      HTTPCookie.AcceptPolicy可选值有always、never、onlyFromMainDocumentDomain,如果要自行解析,设置为HTTPCookie.AcceptPolicy.never,然后从allHeaderFields用cookies(withResponseHeaderFields:for:) 方法解析出cookies。

    2. httpShouldSetCookies:确定请求是否应该包好来自Cookie存储的Cookie。默认是true。

    3. httpCookieStorage:管理cookie存储的单一对象(共享实例)。
      一般在对接多个服务时需要解析响应的cookie,这时候就根据domain和name来解析相应的cookie。

    设置安全策略

    1. tlsMaximumSupportedProtocol: 次会话中进行连接时客户端应请求的最大TLS协议版本。

    2. tlsMinimumSupportedProtocol:协议协商期间应该接受的最小TLS协议。

    3. urlCredentialStorage:提供身份验证凭据的凭证存储。
      (1)根据configuration的这个属性来确定会话内任务使用的凭据存储对象。
      (2)如果不希望使用凭据存储,将此属性设置为nil。
      (3)对于default 和 background sessions,默认值是共享凭据存储对象。
      (4)对于ephemeral sessions,默认值是一个私有凭据存储对象,该对象只在内存中存储数据,当您的会话无效时将销毁该对象。
      urlCredentialStorage涉及到身份认证、认证挑战类容。后续会有详细篇幅介绍。

    设置缓存策略

    1. urlCache:用于向会话中的请求提供缓存响应的URL缓存。
      (1)configuration根据urlCache来确定会话内任务使用的URL缓存对象。
      (2)若要禁用缓存,请将此属性设置为nil。
      (3)default sessions默认共享URL缓存对象。
      (4)background sessions默认缓存对象为nil。
      (5)ephemeral sessions只在内存中存储数据的私有缓存对象。当会话失效时,该对象销毁。

    2. requestCachepolicy:一个预定义常量,用于确定何时从缓存中返回响应。
      (1)configuration根据requestCachepolicy的值来确定会话内任务使用的请求缓存策略。
      (2)CachePolicy指定缓存策略是否依赖于过期时间、年龄、是否应该完全禁用缓存以及是否应该与服务器联系以确定自上次请求依赖内容是否发生了变更。
      (3)默认值是NSURLRequest.CachePolicy.useProtocolCachePolicy。

    支持后台转移

    1. sessionSendsLauchEvents:一个bool,只是在传输完成时是否应该在后头继续或启动应用程序。
    2. isDiscretionary:一个bool用于确定是否可以根据系统的判断来调度后台任务以获得最佳性能。

    支持自定义协议

    1. protocolClasses:在会话中处理请求的额外协议子类的数组。
    2. URLProtocol:一个NSURLProtocol对象处理加载协议特定的URL数据。在NSURLProtocol类本身是一个抽象类,可以为特定URL方案的URL处理基础设施。您可以为您的盈盈支持的任何自定义协议或者URL方案创建子类。

    支持多路TCP

    1. multipathServiceType:指定用于通过Wi-Fi和蜂窝接口传输数据的多路径TCP连接策略的服务类型。
    2. URLSessionConfiguration.MultipathServiceType:指定多路径TCP使用的服务类型的常量。

    设置HTTP策略和代理属性

    1. httpMaximumConnectionsPerHost:公式连接到给定主机的最大数量。
    2. httpShouUsePipelining: 一个bool值,用于确定会话是否应使用http流水线。
    3. connectionProxyDictionary:包含有关在此会话中使用的代理信息的字典。

    4 URLSessionTask

    1. URLSessionTask。

    为具体的网络任务

    1. URLSessionUploadTask:上传硬盘中的文件到服务器,一般是Http post或put。
    1. URLSessionDownloadTask:从远处服务器下载文件到临时文件位置。
    1. URLSessionStreamTask:通过流文件传输。

    5 URLSessionDelegate

    设置URLSession回调代理。对于不同的Task使用相应类型的Delegate的。
    delegate的继承关系URLSessionDelegate <- URLSessionTaskDelegate。URLSessionDataDelegate、URLDownLoadDelegate、URLSessionStreamDelegate等继承自URLSessionTaskDelegate。

    1. URLSessionDelegate:
    2. URLSessionTaskDelegate:
    3. URLSessionDataDelegate:
    4. URLDownLoadDelegate:
    5. URLSessionStreamDelegate:

    6 NSURLRequestCachePolicy

    1. NSURLRequestUseProtocolCahcePolicy。
      (1)如果一个NSCachedURLResponse对于请求并不存在,数据将会从源端获取。
      (2)如果请求拥有一个缓存的响应,那么URL加载系统会检查这个响应来决定,如果它指向内容必须重新生效的话。
      (3)如果内容必须重新生效,将建立一个连向源端的链接来查看内容是否发生变换。键入内容没有变化,那么响应就从本地缓存返回数据。
      (4)如果内容发生变化,那么数据将从源端获取。

    2. NSURLRequestReloadIgnoringLocalCacheData
      (1)加载源数据,不适用本地缓存数据。

    3. NSURLRequestReloadIgnoringLocalAndRemoteCacheData
      (1)本地缓存数据、代理和其他中介都要护士他们的缓存,直接加载源数据。

    4. NSURLRequestReloadIgnoringCacheData=NSURLRequestReloadIgnoringLocalCacheDate

    5. NSURLRequestReturnCacheDataElseLoad
      (1)指定已缓存数据来响应请求,不管他的生命时长和过期时间。
      (2)如果在缓存中没有已存数据来响应请求的话,数据从源端加载。

    6. NSURLRequestReturnCacheDataDontLoad
      (1)指定已缓存的数据来响应请求,不管生命时长和过期时间。
      (2)如果在缓存中没有已存数据来响应URL加载请求,不去尝试从源端加载数据,此时任务加载请求失败。这个常量指定一个类似于离线模式的行为。

      一般很少使用该模式

    7. NSURLRequestReloadRevalidatiingCacheData
      如果已存的缓存数据被源端确认为有效(未过期、生命时长允许等)则允许使用缓存数据响应请求,否则从源段加载数据。

    相关文章

      网友评论

          本文标题:Alamofire框架解读(一)--关于URLSession

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