HTTP使用詳解

聲明:本文轉載 編程小翁 原創, HTTP in iOS你看我就夠。

HTTP屬于老話題了,在項目中我們經常需要往服務端發POST或者GET請求,但是對于HTTP的了解不應只局限于此。千里之行,始于足下。越想走的遠,基本原理就應該了解的透徹全面一些,僅僅停留在使用ASIHttpRequest或者AFNetWorking傳個參數發個請求的程度上是不夠的。這篇文章就是帶你全方面回顧一下HTTP。通過本文你能收獲哪些內容:
·完整HTTP請求與響應包含的必要元素·HTTP不同版本之間的差異·HTTP、Socket、TCP的區別(易混)

一、HTTP協議

HTTP本質上是一種協議,全稱是Hypertext Transfer Protocol,即超文本傳輸協議。從名字上可以看出該協議用于規定客戶端與服務端之間的傳輸規則,所傳輸的內容不局限于文本(其實可以傳輸任意類型的數據)。


二、HTTP請求與響應的內容

當我們往服務端發送一條HTTP請求時都發送了哪些東西過去呢?先看一個POST請求的示例圖:


注:本文使用Paw來模擬發送HTTP請求,使用Charles抓包,Charles選中"Request"以及"Raw"選項就可以看到請求的全部內容

以上示例圖中其實已經包含了一個HTTP請求所必備的幾大要素:請求行、請求頭(headerField)、請求體(body);同理,響應也有狀態行、響應頭、實體內容。接下來我們逐個展開。

1、請求行

請求行包含請求方法(Method)、請求統一資源標識符(URI)、HTTP版本號,如圖2.1第一行所示:


  • 請求方法就是我們所熟悉的POST、GET、HEAD、PUT等

  • URI就是URL中排除掉Host剩下的部分,也就是資源在服務器本地上的路徑

  • HTTP版本號,目前主流的版本是1.1(1999年開始采用),最新的版本是2.0(2015年5月發布)。不同版本之間差異下面會再展開

2、請求頭

請求頭主要存放對客戶端想給服務端的附加信息,下圖框框的部分就是請求頭:


HTTP請求在iOS中用NSURLRequestNSMutableRequest表示;HTTP響應用NSHTTPURLResponse
表示。

  • Host: 目標服務器的網絡地址

  • Accept: 讓服務端知道客戶端所能接收的數據類型,如text/html */*

  • Content-Type: body中的數據類型,如application/json; charset=UTF-8

  • Accept-Language: 客戶端的語言環境,如zh-cn

  • Accept-Encoding: 客戶端支持的數據壓縮格式,如gzip

  • User-Agent: 客戶端的軟件環境,我們可以更改該字段為自己客戶端的名字,比如QQ music v1.11
    ,比如瀏覽器Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/600.8.9 (KHTML, like Gecko) Maxthon/4.5.2

  • Connection: keep-alive,該字段是從HTTP 1.1才開始有的,用來告訴服務端這是一個持久連接,“請服務端不要在發出響應后立即斷開TCP連接”。關于該字段的更多解釋將在后面的HTTP版本簡介
    中展開。

  • Content-Length: body的長度,如果body為空則該字段值為0。該字段一般在POST請求中才會有。

POST請求的body請求體也有可能是空的,因此POST中Content-Length也有可能為0

  • Cookie: 記錄者用戶信息的保存在本地的用戶數據,如果有會被自動附上

值得一提的是,在iOS中當你發送一個任意請求時,不管你愿不愿意,NSURLRequest都會自動幫你記錄你所訪問的URL上設置的cookie。在iOS中用NSHTTPCookieStorage表示,是一個單例。通過NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];for (NSHTTPCookie *cookie in [cookieJar cookies]) { NSLog(@"%@", cookie);}
可以獲取目前被自動保存的所有cookie。對cookie的操作感興趣的請移步IOS中http請求使用cookie這篇文章。

以上就是我們日常開發中比較經常遇到的請求頭,其實還有其他的field,但篇幅所限無法一一列出,想了解所有請求頭請看這里請求頭響應頭列表。那在iOS中如何設置添加這些field呢?可以使用-[NSMutableURLRequest addValue: forHTTPHeaderField:]方法,獲取當前請求已經設置的field可以用-[NSURLRequest allHTTPHeaderFields]。也就是我們可以通過以上接口定制我們所需要的請求頭,但是有些field是不能改的,我們看一下iOS的描述:

從文檔中我們可以看到,在iOS中不應當對Authorization Connection Host WWW-Authenticate這幾個header field做更改。

3、請求體

真正需要發給服務端的數據,在使用POST-multipart上傳請求中請求體就是上傳文件的二進制NSData類型數據;在GET請求中請求體為空;在普通的POST請求中請求體就是一些表單數據。在iOS中一般用NSURLRequestNSMutableURLRequestHTTPBody屬性表示,添加body用-[NSMutableURLRequest setHTTPBody:]。

4、響應狀態行

狀態行是服務端返回給客戶端的狀態信息,包含HTTP版本號、狀態碼、狀態碼對應的英文名稱。以下就是典型的正確狀態行:HTTP/1.1 200 OK這個部分需要講的是錯誤碼。事實上HTTP請求錯誤碼可以根據錯誤碼從左往右第一個數字大致分為以下幾類:

  • 1XX:信息提示。不代表成功或者失敗,表示臨時響應,比如100表示繼續,101表示切換協議
  • 2XX: 成功
  • 3XX: 重定向
  • 4XX:客戶端錯誤,很有可能是客戶端發生問題,如親切可愛的404表示未找到文件,說明你的URI是有問題的,服務器機子上該目錄是沒有該文件的;414
    URI太長
  • 5XX: 服務器錯誤,比如504網關超時

錯誤碼是不用去記的,出錯了再查對應的錯誤碼含義就行。但是知道上面的分類有助于第一時間做出大體的判斷,起碼你能清楚是服務端還是客戶端的原因。

5、響應頭與響應實體

這部分與請求部分差異不大,響應頭的字field會有稍許不同,響應頭中的header field同樣移步請求頭響應頭列表。

三、HTTP版本簡介

這里我把HTTP版本簡單分為三類:1.1之前,1.1,2.0,針對這三類做個主要差異的介紹:

HTTP 1.1之前

  • 不支持持久連接。一旦服務器對客戶端發出響應就立即斷開TCP連接
  • 無請求頭跟響應頭
  • 客戶端的前后請求是同步的。下一個請求必須等上一個請求從服務端拿到響應后才能發出,有點類似多線程的同步機制。

HTTP 1.1(主流版本) 與1.1之前的版本相比,做了以下性能上的提升

  • 增加請求頭跟響應頭
  • 支持持久連接??蛻舳送ㄟ^請求頭中指定Connectionkeep-alive告知服務端不要在完成響應后立即釋放連接。HTTP是基于TCP的,在HTTP 1.1中一次TCP連接可以處理多次HTTP請求
  • 客戶端不同請求之間是異步的。下一個請求不必等到上一個請求回來后再發出,而可以連續發出請求,有點類似多線程的異步處理。

HTTP 2.0本著向下兼容的原則,

  • 1.1版本有的特性2.0都具備,也使用相同的API。但是2.0將只用于https網址。由于2.0的普及還需要比較長的一段時間,這里不展開,更多新特性請參考這篇文章。

我們重點關注一下當前1.1版本所做幾點改變。支持持久連接有什么好處呢?HTTP是基于TCP連接的,如果連接被頻繁地啟動然后斷開就會花費很多資源在TCP三次握手以及四次揮手上,效率低下。以請求一個網頁為例,我們知道,一個html網頁上的圖片資源并不是直接嵌入在網頁上,而只是提供url,圖片仍需要額外發HTTP 請求去下載。一個網頁從請求到最終加載到本地往往需要經過過個HTTP請求。在1.1版本之前請求一個網頁就需要發生多次"握手-揮手"的過程,每次連接之間相互獨立;而1.1及之后的版本最少只需要一次就夠。再來就是請求異步,其好處參考多線程異步處理,在此不展開。以上特性可以用圖2.3表示:


我們可以看到:1、N次請求其實只建立了1次TCP連接,2、N次請求連續異步發出。

四、HTTP、Socket、TCP的區別

這三個概念經常被談到,也是比較容易被混掉的概念。在回顧之前我們先看一下這三者在TCP/IP協議族中的位置關系:


HTTP是應用層的協議,更靠近用戶端;TCP是傳輸層的協議;而socket是從傳輸層上抽象出來的一個抽象層,本質是接口。所以本質上三種還是很好區分的。盡管如此,有時候你可能會懵逼,HTTP連接、TCP連接、socket連接有什么區別?好吧,如果上面的圖解釋的還是不夠清楚的話,我們繼續往下看。

1、TCP連接與HTTP連接的區別

上文提過,HTTP是基于TCP的,客戶端往服務端發送一個HTTP請求時第一步就是要建立與服務端的TCP連接,也就是先三次握手,“你好,你好,你好”。從HTTP 1.1開始支持持久連接,也就是一次TCP連接可以發送多次的HTTP請求。

小總結:HTTP基于TCP

2、TCP連接與Socket連接的區別

在圖4.1中我們提到,socket層只是在TCP/UDP傳輸層上做的一個抽象接口層,因此一個socket連接可以基于TCP,也有可能基于UDP?;赥CP協議的socket連接同樣需要通過三次握手建立連接,是可靠的;基于UDP協議的socket連接不需要建立連接的過程,不過對方能不能收到都會發送過去,是不可靠的,大多數的即時通訊IM都是后者。

小總結:Socket也可以基于TCP

3、HTTP連接與Socket連接的區別

區分這兩個概念是比較有意義的,畢竟TCP看不見摸不著,HTTP與Socket是實實在在能用到的。

  • HTTP是短連接,Socket(基于TCP協議的)是長連接。盡管HTTP1.1開始支持持久連接,但仍無法保證始終連接。而Socket連接一旦建立TCP三次握手,除非一方主動斷開,否則連接狀態一直保持。

  • HTTP連接服務端無法主動發消息,Socket連接雙方請求的發送先后限制。這點就比較重要了,因為它將決定二者分別適合應用在什么場景下。HTTP采用“請求-響應”機制,在客戶端還沒發送消息給服務端前,服務端無法推送消息給客戶端。必須滿足客戶端發送消息在前,服務端回復在后。Socket連接雙方類似peer2peer的關系,一方隨時可以向另一方喊話。

4、問題來了:什么時候該用HTTP,什么時候該用socket

這個問題的提出是很自然而然的。當你接到一個與另一方的網絡通訊需求,自然會考慮用HTTP還是用Socket。

  • 用HTTP的情況:雙方不需要時刻保持連接在線,比如客戶端資源的獲取、文件上傳等

  • 用Socket的情況:大部分即時通訊應用(QQ、微信)、聊天室、蘋果APNs等

在iOS中,發HTTP請求一般用原生的NSURLConnection、NSURLSession或者開源的AFNetWorking(推薦)、ASIHttpRequest(已停止更新)。連接Socket連接我用的比較多是robbiehanson大神的CocoaAsyncSocket (XMPPFramework
也是出自他手)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,214評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,781評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,588評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,315評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,699評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,882評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,441評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,189評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,388評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,613評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,023評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,310評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,112評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,334評論 2 377

推薦閱讀更多精彩內容