
文章目錄
- 一. HTTP發展史
- 二. HTTP簡介
- 三. HTTPS簡介
- 四. HTTP與HTTPS區別
- 五. 代碼部分
- 1. 簡單請求
- 2. 上傳資料
- 3. 下載資料
- 4. 后臺下載
一. HTTP發展史
| HTTP版本 | 年份 | 新增命令 | 連接方式 | 摘要 |
|---|---|---|---|---|
| 0.9 | 1991 | GET | 短連接 | 初版 |
| 1.0 | 1996 | POST、HEAD | 短連接 (非標準長連接Connection: keep-alive) | 1. 可以傳輸文字,還能傳輸影像、視頻、二進制檔案, 2. 加入頭資訊、狀態碼、多字符集支持、多部分發送、權限、快取、內容編碼等, |
| 1.1 | 1999 | PUT、PATCH、TRACE、OPTIONS、DELETE | 默認持久連接 | 1. 管道機制: 一個連接可同時發送多個請求(服務器端需要按順序回傳結果), 2. 增加Host欄位,指定服務器的域名,這樣服務器上支持了虛擬主機,即一臺機器多個站點, |
| 2 | 2015 | - | 默認持久連接 | 1. 無論是header還是body都是二進制資料(打包成幀frame), 2. 在一個連接里,客戶端和服務端同時發送多個請求,為了區分它們就需要對資料做標記, 3. 支持header資訊索引, 4. 支持服務端主動推送功能, |
二. HTTP簡介
HTTP協議是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫, 是用于從萬維網(WWW:World Wide Web )服務器傳輸超文本到本地瀏覽器的傳送協議,
HTTP基于TCP/IP通信協議來傳遞資料 (HTML檔案, 圖片檔案, 查詢結果等), 默認埠號為80,
HTTP使用統一資源識別符號(Uniform Resource Identifiers, URI)來傳輸資料和建立連接,
請求報文結構
客戶端發送一個HTTP請求到服務器的請求訊息包括以下格式:請求行(request line)、請求頭部(header)、空行和請求資料四個部分組成,下圖給出了請求報文的一般格式,HTTP回應也由四個部分組成,分別是:狀態行、訊息報頭、空行和回應正文,

請求方法
根據 HTTP 標準,HTTP 請求可以使用多種請求方法,
HTTP1.0 定義了三種請求方法: GET, POST 和 HEAD方法,
HTTP1.1 新增了六種請求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法,
| 序號 | 方法 | 描述 |
|---|---|---|
| 1 | GET | 請求指定的頁面資訊,并回傳物體主體, |
| 2 | HEAD | 類似于 GET 請求,只不過回傳的回應中沒有具體的內容,用于獲取報頭 |
| 3 | POST | 向指定資源提交資料進行處理請求(例如提交表單或者上傳檔案),資料被包含在請求體中,POST 請求可能會導致新的資源的建立和/或已有資源的修改, |
| 4 | PUT | 從客戶端向服務器傳送的資料取代指定的檔案的內容, |
| 5 | DELETE | 請求服務器洗掉指定的頁面, |
| 6 | CONNECT | HTTP/1.1 協議中預留給能夠將連接改為管道方式的代理服務器, |
| 7 | OPTIONS | 允許客戶端查看服務器的性能, |
| 8 | TRACE | 回顯服務器收到的請求,主要用于測驗或診斷, |
| 9 | PATCH | 是對 PUT 方法的補充,用來對已知資源進行區域更新, |
三. HTTPS簡介
HTTPS(Hypertext Transfer Protocol Secure:超文本傳輸安全協議)是一種透過計算機網路進行安全通信的傳輸協議,HTTPS 經由 HTTP 進行通信,但利用 SSL/TLS 來加密資料包,HTTPS 開發的主要目的,是提供對網站服務器的身份認證,保護交換資料的隱私與完整性,
HTTPS 默認作業在 TCP 協議443埠.
作業原理:

四. HTTP與HTTPS區別
- HTTP作業在80埠; HTTPS作業在443埠,
- HTTP 明文傳輸,資料都是未加密的,安全性較差; HTTPS(SSL+HTTP) 資料傳輸程序是加密的,安全性較好,
- 使用 HTTPS 協議需要到 CA(Certificate Authority,數字證書認證機構) 申請證書,一般免費證書較少,因而需要一定費用,證書頒發機構如:Symantec、Comodo、GoDaddy 和 GlobalSign 等,
- HTTP 頁面回應速度比 HTTPS 快,主要是因為 HTTP 使用 TCP 三次握手建立連接,客戶端和服務器需要交換 3 個包,而 HTTPS除了 TCP 的三個包,還要加上 ssl 握手需要的 9 個包,所以一共是 12 個包,
- HTTPS 其實就是建構在 SSL/TLS 之上的 HTTP 協議,所以,HTTPS 比 HTTP 要更耗費服務器資源,
五. 代碼部分
Apple默認使用HTTPS,如需開啟HTTP,需在info.plist添加如下配置:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

1. 簡單請求
// 創建URLRequest
let url = URL(string: "http://www.baidu.com")
var request = URLRequest.init(url: url!) // 默認 cachePolicy = .useProtocolCachePolicy,timeoutInterval = 60.0
request.httpMethod = "GET" // or HEAD、POST、PUT...
// 創建URLSession
let session = URLSession.shared
// 創建請求任務
let dataTask = session.dataTask(with: request) { (data, response, error) in
NSLog("data:\(String(describing: data)), response:\(String(describing: response)), error:\(String(describing: error))")
}
// 發起請求
dataTask.resume()
以上請求最侄訓轉換成如下真正的請求結構,使用Charles抓到raw資料:
GET / HTTP/1.1
Host: www.baidu.com
Accept: */*
User-Agent: KKHttpDemo/1 CFNetwork/1220.1 Darwin/20.3.0
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive
上面提到了三個要點:URLRequest、URLSession 和 會話任務,
URLRequest
URLRequest封裝了加載請求的兩個基本屬性:要加載的URL和用于加載該請求的策略,此外,對于HTTP和HTTPS請求,URLRequest包括HTTP方法(GET,POST等)和HTTP標頭,
URLRequest除了可設定URL及請求方法,還可定制快取策略cachePolicy、設定請求超時timeoutInterval等,
URLSession
URLSession提供了一系列API用于執行資料傳輸任務,每個App創建一個或多個URLSession實體,每個實體協調一組相關的資料傳輸任務,
URLSession有四種型別:
1. shared單例會話,單例會話沒有會話配置物件(URLSessionConfiguration),即會話不可自定義,通常用于簡單的請求,
2. default默認會話,默認會話與單例會話非常相似,但是您可以對其進行配置,您還可以將委托分配給默認會話以增量獲取資料,
3. ephemeral臨時會話,臨時會話類似于單例會話,但是不會將快取,cookie或憑據寫入磁盤,例如應用于無痕瀏覽,你懂的,😏
4. background后臺會話,后臺會話使您可以在應用未運行時在后臺執行內容的上載和下載,
URLSessionConfiguration
既然介紹了URLSession,那么也應該來了解下URLSessionConfiguration,URLSessionConfiguration作為URLSession的配置屬性,可以進行一些自定義配置,上面提到的default、ephemeral及background都用到了URLSessionConfiguration,
使用URLSessionConfiguration的allowsCellularAccess屬性還可以設定會話是否能通過蜂窩網路進行連接,
會話任務
會話任務(URL Session Tasks)有以下四種,上面例子只是用到的其中一種(dataTask),
1. Data tasks,使用NSData物件發送和接收資料,資料任務旨在向服務器發出簡短的,經常是互動式的請求,
2. Upload tasks,與資料任務相似,但是它們還發送資料(通常以檔案的形式),并在應用程式不運行時支持后臺上傳,
3. Download tasks,以檔案形式檢索資料,并在應用程式不運行時支持后臺下載和上傳,
4. WebSocket tasks,使用RFC 6455中定義的WebSocket協議通過TCP和TLS交換訊息,
2. 上傳資料
// 要上傳的資料
let uploadData = "test123".data(using: .utf8)
// 配置URL請求
let url = URL(string: "http://httpbin.org/post")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
// 使用單例會話
let session = URLSession.shared
// 啟動一個上傳請求
let task = session.uploadTask(with: request, from: uploadData) { data, response, error in
if let error = error {
print ("error: \(error)")
return
}
guard let response = response as? HTTPURLResponse,
(200...299).contains(response.statusCode) else {
print ("server error")
return
}
if let mimeType = response.mimeType,
mimeType == "application/json",
let data = data,
let dataString = String(data: data, encoding: .utf8) {
print ("got data: \(dataString)")
}
}
task.resume()
httpbin.org是一個測驗HTTP請求的GitHub開源網站
log:
got data: {
"args": {},
"data": "test123",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-us",
"Content-Length": "7",
"Content-Type": "text/plain",
"Host": "httpbin.org",
"User-Agent": "KKHttpDemo/1 CFNetwork/1220.1 Darwin/20.3.0",
"X-Amzn-Trace-Id": "Root=1-603317a5-511395fa2f7c282800345ec2"
},
"json": null,
"origin": "113.90.245.35",
"url": "http://httpbin.org/post"
}
3. 下載資料
let url = URL(string: "http://httpbin.org/image/jpeg")!
let downloadTask = URLSession.shared.downloadTask(with: url) {
urlOrNil, responseOrNil, errorOrNil in
if let error = errorOrNil {
print ("error: \(error)")
return
}
guard let fileURL = urlOrNil else { return }
do {
let documentsURL = try
FileManager.default.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false)
var savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent)
// 修改后綴名
savedURL.deletePathExtension()
savedURL.appendPathExtension("jpeg")
// 從tmp檔案夾下移動到documents檔案夾下
try FileManager.default.moveItem(at: fileURL, to: savedURL)
// 生成image
let imageData = try Data.init(contentsOf: savedURL)
let image = UIImage(data: imageData)
if image != nil {
// 重繪UI
DispatchQueue.main.async {
self.imageView?.image = image
}
}
} catch {
print ("file error: \(error)")
}
}
downloadTask.resume()
4. 后臺下載
AppDelegate.swift
var backgroundCompletionHandler: (() -> Void)?
// 下載完成后呼叫:App在后臺還是被系統殺死,都會呼叫,手動殺死App或在前臺時不呼叫
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
backgroundCompletionHandler = completionHandler
}
ViewController.swift
// 后臺下載
func backgroundDownload() {
// 創建后臺URLSession
let config = URLSessionConfiguration.background(withIdentifier: "com.Kang.downloadSession")
config.isDiscretionary = true
config.sessionSendsLaunchEvents = true
let urlSession = URLSession(configuration: config, delegate: self, delegateQueue: nil)
// 開啟下載任務
let url = URL(string: "http://httpbin.org/image/jpeg")!
let backgroundTask = urlSession.downloadTask(with: url)
backgroundTask.earliestBeginDate = Date().addingTimeInterval(5) // 延遲5秒下載
backgroundTask.countOfBytesClientExpectsToSend = 200 // 最大上傳200Byte
backgroundTask.countOfBytesClientExpectsToReceive = 500 * 1024 // 最大下載500KB
backgroundTask.resume()
}
//MARK: - URLSessionDelegate
// 任務完成
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
print(#function, "后臺下載完成")
DispatchQueue.main.async {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate,
let backgroundCompletionHandler = appDelegate.backgroundCompletionHandler else {
return
}
backgroundCompletionHandler() // 告訴系統,已經處理完成
}
}
//MARK: - URLSessionDownloadDelegate
// 下載完成
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print(#function, "下載完成")
let fileURL = location
do {
let documentsURL = try
FileManager.default.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false)
var savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent)
// 修改后綴名
savedURL.deletePathExtension()
savedURL.appendPathExtension("jpeg")
// 從tmp檔案夾下移動到documents檔案夾下
try FileManager.default.moveItem(at: fileURL, to: savedURL)
// 生成image
let imageData = try Data.init(contentsOf: savedURL)
let image = UIImage(data: imageData)
if image != nil {
// 重繪UI
DispatchQueue.main.async {
self.imageView?.image = image
}
}
} catch {
print ("file error: \(error)")
}
}
// 下載進度
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
// 可以將位元組轉化為我們需要的Kb或者Mb
let receiveSize = ByteCountFormatter.string(fromByteCount: totalBytesWritten, countStyle: .file)
let totalSize = ByteCountFormatter.string(fromByteCount: totalBytesExpectedToWrite, countStyle: .file)
let status = receiveSize + " / " + totalSize
print("process: \(status)")
// 重繪UI
DispatchQueue.main.async {
self.statusLabel?.text = status
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/263440.html
標籤:其他
上一篇:web頁面錄制與回放全堆疊小專案
下一篇:資料結構概述
