本文主要是看了
- WWDC 2015 - Session 711 - Networking with NSURLSession
- WWDC 2016 - Session 711 - NSURLSession: New Features and Best Practices
做出的翻譯和總結, 文字/視頻鏈接如下 :
- wwdc2015/711 : Networking with NSURLSession
- wwdc2016/711 : NSURLSession: New Features and Best Practices
App Transfer Security
iOS9新特性. 核心是防止用戶的個人隱私數(shù)據(jù)被意外泄漏. 加強默認Configuration的安全性.
HTTP
以前HTTP請求是明文傳輸(clearText)的, 別人攔截請求之后就能獲取所有信息.
HTTPS
HTTPS通過在TCP于HTTP層之間加入一層SSL/TLS層, 能做到 :
- Encryption : 信息加密傳輸, 別人看不懂
- Integrity : 保證數(shù)據(jù)完整性, 即第三方篡改后能檢測出來
- Authentication : 身份驗證, 防止第三方偽造通信
HTTPS in iOS
蘋果希望所有所有請求都使用HTTPS來加強安全性, 但是也有以下幾種例外(以下全部可以在info.plist文件中配置) :
- 全局HTTPS請求, 但是某個域名采用HTTP請求
NSAppTransportSecurity
NSAllowsArbitraryLoads = NO // 默認為NO, 這一行不要也行
NSExceptionDomains
"media.example.com"
NSExceptionAllowsInsecureHTTPLoads = YES - 全局HTTP請求, 但是某個域名采用HTTPS請求
NSAppTransportSecurity
NSAllowsArbitraryLoads = YES
NSExceptionDomains
"secure.example.com"
NSExceptionAllowsInsecureHTTPLoads = NO - 全局HTTP/HTTPS(任意)請求
NSAppTransportSecurity
NSAllowsArbitraryLoads = YES

使用NSAllowsArbitraryLoads可以檢測app中加載失敗是不是因為ATS的原因.
CFNetwork中用于網(wǎng)絡診斷的環(huán)境變量CFNETWORK_DIAGNOStICS = 1 : 所有加載失敗的URL都能被確定是URL錯誤還是底層TLS錯誤. 這樣能進一步排查錯誤.
下面為ATS新增的屬性
NSAllowsArbitraryLoadsInWebContent : UIWebView會無視app的其他協(xié)議, 加載HTTP的內(nèi)容. 僅限于UIWebVie對象, 其他對象還是對遵循安全協(xié)議.
NSRequiresCertificateTransparency : 保證證書的合法性.
NSURLSession新特性
NSURLSession將全面支持HTTP/2 !

為什么需要HTTP/2
由于HTTP/1.1存在許多問題 :
-
單路連接 請求低效
- 每個TCP連接只能對應一個HTTP請求, 每個HTTP請求只請求一個資源, 瀏覽器只能通過建立多個TCP連接來解決, 但是由于文本協(xié)議開銷, 缺乏頭壓縮, 意味著對客戶端和服務器的要求更高且性能更低下
HTTP/1.1 without pipelining- 使用HTTP管道, 但是HTTP管道并不適用于所有的服務器或網(wǎng)絡, 實際上在很多瀏覽器上是被禁止的. 事實上效率并不高.
HTTP/1.1 with pipelining
- HTTP只允許由客戶端主動發(fā)起請求
- 意味著缺少預加載的功能
- HTTP頭冗余
- 每次發(fā)送HTTP請求都有一堆重復的header value
了解HTTP/2

HTTP/2 有什么改進 :
- 一個TCP連接能發(fā)起多個HTTP請求
- 實現(xiàn)完全多路復用, 意味著一個新的請求不用等到上一個請求得到響應之后再發(fā)出
- 有請求優(yōu)先級, 所以能把重要的資源優(yōu)先提供給擁有更高權限的客戶端.
- 使用二進制分幀, 使得數(shù)據(jù)的處理和解析速度更快.
- 使用
HPACK頭壓縮技術- 使用一個靜態(tài)表和一個動態(tài)表
- 靜態(tài)表包含最常用的HTTP信息頭, 并且不可修改
- 包含在靜態(tài)表中的信息頭可以動態(tài)添加到動態(tài)表中, 動態(tài)表中的信息頭通過指針引用靜態(tài)表中的信息
- HTTP/2自動支持HTTPS, 意味著HTTP/2是安全的
- 支持服務器自推送
HTTP/2 多路復用
Q : HTTP/2多路復用是如何隊首阻塞的問題的?
A : 在HTTP/1.1的時候曾試過采用HTTP pipelining (HTTP 管道/流水線 技術)能實現(xiàn)同一TCP連接中不用等待舊請求的響應就可以發(fā)送新請求. 但是HTTP pipelining有個致命的缺點 : HTTP響應仍然是按照請求的順序依次收到.
HTTP/2 多路復用+請求優(yōu)先級, 發(fā)送的時候還是依次發(fā)送請求, 但是與此同時我們同時得到了回復, 同時, 更高優(yōu)先級的請求我們得到以及發(fā)送給客戶端的速度更快, 如下圖所示 :

服務器自推送
在HTTP/1.1時代, 我們沒有服務器自推送, 只能發(fā)一個請求, 得到響應之后再發(fā)第二個請求... 延遲可想而知 :

而在HTTP/2時代, 我們有了服務器自推送, 服務器會把相關聯(lián)的數(shù)據(jù)全部push給我們 :

性能馬上強了一大截, 我們再也不用像以前那樣苦苦等待了.
并且這功能已經(jīng)內(nèi)嵌在NSURLSession中, 我們不需要寫任何一行代碼來支持其實現(xiàn).
iOS中適配HTTP/2
NSURLSession已經(jīng)自動支持HTTP/2, 客戶端不需要額外寫任何代碼. 只需要一臺支持HTTP/2通信的服務器即可. 哎呀, 要是沒有怎么辦, 也沒關系, 看下面 :
- 服務器支持HTTP/2
- NSURLSession自動使用HTTP/2進行通信
- 服務器不支持HTTP/2
- NSURLSession自動使用HTTP/1.1或其他更優(yōu)的協(xié)議
我們一句代碼, 判斷都不用寫, 省事又省心.
SPDY
這里說句題外話, 雖然SPDY并不在該Session中提及, 但是與HTTP/2有異曲同工之處, SPDY在之前被認為是未來的HTTP/2, 所以這里說一下.
SPDY是Google開發(fā)的基于TCP的應用層協(xié)議, 通過頭部壓縮, 多路復用和優(yōu)先級來縮短網(wǎng)頁的加載時間和提高安全性. 可以說是HTTP/1.1的一個優(yōu)化版.
- 多路復用, 請求優(yōu)化
- 支持服務器推送技術
- SPDY壓縮了HTTP頭
- 強制使用SSL傳輸協(xié)議
更多有關SPDY的詳情請見這里
驚 ! iOS9開始蘋果棄用NSURLConnection, 不再維護NSURLConnection, 所有有關Networking的新API只會在NSURLSession上更新.

NSURLSession的新功能
cookie 共享
增加sessionCookieGroup以實現(xiàn)app與其擴展(例如通知中心等等)之間cookie的共享.
let ident = "group.mycompany.mygroupname"
let cookieStorage = NSHTTPCookieStorage.sharedCookieStorageForGroupContainerIdentifier(
identifier: ident)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
config.HTTPCookieStorage = cookieStorage
let session = NSURLSession(configuration: config)
NSURLSessionStreamTask
以前我們使用NSInputStream/NSOutputStream來進行一些非HTTP的連接, 例如利用TCP連接一臺遠程的服務器等等, 現(xiàn)在我們有了NSURLSessionStreamTask讓我們更簡單地實現(xiàn)以上功能.
NSURLSessionStreamTask的特性 :
- 更輕松地使用TCP進行通信
- 替代NSInputStream/NSOutputStream, 提供更優(yōu)的API
- 異步讀寫API
- 內(nèi)置強大的支持功能, 能自動通過HTTP代理, 連接一個遠程服務器.
- 輕松轉換成NSStream
NSURLSessionTaskMetrics
對發(fā)送請求/DNS查詢/TLS握手/請求響應等各種環(huán)節(jié)時間上的統(tǒng)計. 更易于我們檢測, 分析我們的請求緩慢到底是發(fā)生在哪個環(huán)節(jié), 并對此進行優(yōu)化提升我們APP的性能.
下面開始介紹NSURLSessionTaskMetrics的屬性
Property
taskInterval : 任務從開始到結束總共用的時間
redirectCount : 任務重定向的次數(shù)
transactionMetrics : 在任務執(zhí)行期間產(chǎn)生的每個請求/響應事務, 它是一個裝著許多
NSURLSessionTaskTransactionMetrics對象的數(shù)組
NSURLSessionTaskTransactionMetrics
property
request and response : 請求和響應
-
networkProtocolName : 網(wǎng)絡協(xié)議名稱
- http/1.1
- http/2
- spdy/3, spdy/3.1
isProxyConnection : 是否連接代理服務器
isReusedConnection : 是否允許重連
-
resourceFetchType : 描述本次加載的類型, 枚舉類型
- networkLoad : 網(wǎng)絡加載
- localCache : 本地緩存
- serverPush : 服務器自推送
-
Connection Establishment and Transmission
transmissionsfetchStart : 開始發(fā)起請求.
domainLookupStart : 發(fā)送DNS請求, 域名->IP地址
domainLookupEnd : DNS請求完成, 拿到IP地址
-
connectStart : 與遠程服務器開始建立TCP連接
- secureConnectionStart : HTTPS的TLS握手開始
- secureConnectionEnd : HTTPS的TLS握手完成
connectEnd : 與服務器建立起了TCP連接
requestStart : 開始傳輸HTTP header第一個字節(jié)的時間(遠程/緩存)
requestEnd : HTTP最后一個字節(jié)傳輸完成的時間(遠程/緩存)
responseStart : 從服務器得到數(shù)據(jù)(遠程/緩存)
responseEnd : 從服務器接受完最后一個字節(jié)的數(shù)據(jù)(遠程/緩存)
另外, 需要注意的是, 如果請求命中了cache, 上述很多值會為nil.
API
NSURLSessionTaskDelegate代理中新增一個方法- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics, 當收集完成的時候就會調用該方法.
我們只需要實現(xiàn)代理的這個方法就能在這里做統(tǒng)計, 輸出等等操作.
Something else
蘋果不再支持RC4加密.
以上圖片均來自官方WWDC中的PDF.


