天天看點

Android網絡程式設計(一)HTTP協定原理

前言

這篇文章是這個系列的開篇,作為移動開發人員,開發的應用不免會對網絡進行訪問。盡管如今已經有非常多的開源庫幫助我們能夠輕而易舉的訪問網絡,可是我們仍要去了解網絡訪問的原理,這也是一個優秀開發人員所必備的知識點。這篇文章我們就先來了解一下HTTP協定原理。

1.HTTP簡單介紹

HTTP是一個屬于應用層的面向對象的協定,因為其簡捷、高速的方式。适用于分布式超媒體資訊系統。

它于1990年提出,經過幾年的使用與發展。得到不斷地完好和擴充。

HTTP協定的主要特點

  1. 支援C/S(客戶/server)模式。
  2. 簡單高速:客戶向server請求服務時,僅僅需傳送請求方法和路徑。請求方法經常使用的有GET、HEAD、POST。每種方法規定了客戶與server聯系的類型不同。因為HTTP協定簡單,使得HTTPserver的程式規模小,因而通信速度非常快。
  3. 靈活:HTTP同意傳輸随意類型的資料對象。正在傳輸的類型由Content-Type加以标記。
  4. 無連接配接:無連接配接的含義是限制每次連接配接僅僅處理一個請求。server處理完客戶的請求。并收到客戶的應答後,即斷開連接配接。採用這樣的方式能夠節省傳輸時間。
  5. 無狀态:HTTP協定是無狀态協定,無狀态是指協定對于事務處理沒有記憶能力。缺少狀态意味着假設興許處理須要前面的資訊,則它必須重傳,這樣可能導緻每次連接配接傳送的資料量增大。還有一方面,在server不須要先前資訊時它的應答就較快。

HTTP URL 的格式例如以下

http://host[":"port][abs_path]      

http表示要通過HTTP協定來定位網絡資源;host表示合法的Internet主機域名或者IP位址。port指定一個端口号,為空則使用預設端口80。abs_path指定請求資源的URI(Web上随意的可用資源)。

HTTP有兩種封包各自是請求封包和響應封包。讓我們先來看看請求封包。

2.HTTP的請求封包

先來看看請求封包的一般格式:

Android網絡程式設計(一)HTTP協定原理

通常來說一個HTTP請求封包由請求行、請求報頭、空行、和請求資料4個部分組成。

請求行

請求行由請求方法,URL字段和HTTP協定的版本号組成。格式例如以下:

Method Request-URI HTTP-Version CRLF      

當中 Method表示請求方法;Request-URI是一個統一資源辨別符;HTTP-Version表示請求的HTTP協定版本号;CRLF表示回車和換行(除了作為結尾的CRLF外,不同意出現單獨的CR或LF字元)。

HTTP請求方法有8種。各自是GET、POST、DELETE、PUT、HEAD、TRACE、CONNECT 、OPTIONS。當中PUT、DELETE、POST、GET分别相應着增删改查。對于移動開發最經常使用的就是POST和GET了。

  1. GET:請求擷取Request-URI所辨別的資源
  2. POST:在Request-URI所辨別的資源後附加新的資料
  3. HEAD:請求擷取由Request-URI所辨別的資源的響應消息報頭
  4. PUT: 請求server存儲一個資源。并用Request-URI作為其辨別
  5. DELETE :請求server删除Request-URI所辨別的資源
  6. TRACE : 請求server回送收到的請求資訊。主要用于測試或診斷
  7. CONNECT: HTTP/1.1協定中預留給能夠将連接配接改為管道方式的代理server。
  8. OPTIONS :請求查詢server的性能。或者查詢與資源相關的選項和需求

比如我去訪問我的CSDN部落格位址請求行是:

GET javascript:void(0) HTTP/1.1      

請求報頭

在請求行之後會有0個或者多個請求報頭,每一個請求報頭都包括一個名字和一個值,它們之間用“:”切割。請求頭部會以一個空行,發送回車符和換行符,通知server以下不會有請求頭。關于請求報頭,會在後面的消息報頭一節做統一的解釋。

請求資料

請求資料不在GET方法中使用。而是在POST方法中使用。

POST方法适用于須要客戶填寫表單的場合,與請求資料相關的最經常使用的請求頭是Content-Type和Content-Length。

3.HTTP的響應封包

先來看看響應封包的一般格式:

Android網絡程式設計(一)HTTP協定原理

HTTP的響應封包由狀态行、消息報頭、空行、響應正文組成。

響應報頭後面會講到,響應正文是server傳回的資源的内容,先來看看狀态行。

狀态行

1、狀态行格式例如以下:

HTTP-Version Status-Code Reason-Phrase CRLF      

當中,HTTP-Version表示serverHTTP協定的版本号。Status-Code表示server發回的響應狀态代碼。Reason-Phrase表示狀态代碼的文本描寫叙述。

狀态代碼有三位數字組成,第一個數字定義了響應的類别,且有五種可能取值:

  • 100~199:訓示資訊,表示請求已接收,繼續處理
  • 200~299:請求成功。表示請求已被成功接收、了解、接受
  • 300~399:重定向,要完畢請求必須進行更進一步的操作
  • 400~499:client錯誤。請求有文法錯誤或請求無法實作
  • 500~599:server端錯誤,server未能實作合法的請求

常見的狀态碼例如以下:

  • 200 OK:client請求成功
  • 400 Bad Request:client請求有文法錯誤,不能被server所了解
  • 401 Unauthorized:請求未經授權,這個狀态代碼必須和WWW-Authenticate報頭域一起使用
  • 403 Forbidden:server收到請求。可是拒絕提供服務
  • 500 Internal Server Error:server發生不可預期的錯誤
  • 503 Server Unavailable:server目前不能處理client的請求。一段時間後可能恢複正常

比如訪問我的CSDN部落格位址響應的狀态行是:

HTTP/1.1 200 OK      

4.HTTP的消息報頭

消息報頭分為通用報頭、請求報頭、響應報頭、實體報頭等。消息頭由鍵值對組成,每行一對。關鍵字和值用英文冒号“:”分隔。

通用報頭

既能夠出如今請求報頭,也能夠出如今響應報頭中

  • Date:表示消息産生的日期和時間
  • Connection:同意發送指定連接配接的選項。比如指定連接配接是連續的。或者指定“close”選項,通知server,在響應完畢後,關閉連接配接
  • Cache-Control:用于指定緩存指令,緩存指令是單向的(響應中出現的緩存指令在請求中未必會出現)。且是獨立的(一個消息的緩存指令不會影響還有一個消息處理的緩存機制)

請求報頭通知server關于client求求的資訊,典型的請求頭有:

  • Host:請求的主機名,同意多個域名同處一個IP位址,即虛拟主機
  • User-Agent:發送請求的浏覽器類型、作業系統等資訊
  • Accept:client可識别的内容類型清單,用于指定client接收那些類型的資訊
  • Accept-Encoding:client可識别的資料編碼
  • Accept-Language:表示浏覽器所支援的語言類型
  • Connection:同意client和server指定與請求/響應連接配接有關的選項,比如這是為Keep-Alive則表示保持連接配接。
  • Transfer-Encoding:告知接收端為了保證封包的可靠傳輸。對封包採用了什麼編碼方式。

響應報頭

用于server傳遞自身資訊的響應,常見的響應報頭:

  • Location:用于重定向接受者到一個新的位置,經常使用在更換域名的時候
  • Server:包括可server用來處理請求的系統資訊。與User-Agent請求報頭是相相應的

實體報頭

實體報頭用來定于被傳送資源的資訊,既能夠用于請求也可用于響應。請求和響應消息都能夠傳送一個實體。常見的實體報頭為:

  • Content-Type:發送給接收者的實體正文的媒體類型
  • Content-Lenght:實體正文的長度
  • Content-Language:描寫叙述資源所用的自然語言,沒有設定則該選項則覺得實體内容将提供給全部的語言閱讀
  • Content-Encoding:實體報頭被用作媒體類型的修飾符。它的值訓示了已經被應用到實體正文的附加内容的編碼,因而要獲得Content-Type報頭域中所引用的媒體類型,必須採用相應的解碼機制。
  • Last-Modified:實體報頭用于訓示資源的最後改動日期和時間
  • Expires:實體報頭給出響應過期的日期和時間

5.應用舉例

要想檢視網頁或者手機請求網絡的請求封包和響應封包有非常多種方法,這裡推薦採用Fiddler,在​​Android利用Fiddler進行網絡資料抓包​​這篇文章中詳盡介紹了怎樣使用Fiddler。在這裡就不贅述了。

打開Fiddler,然後用浏覽器訪問我的CSDN部落格站點:

Android網絡程式設計(一)HTTP協定原理

點選紅色畫筆的區域就能夠看到請求封包和響應封包了

請求封包:

//請求行
Host: blog.csdn.net                                                       //請求報頭
Connection: keep-alive
Cache-Control: max-age=0       
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36 QQBrowser/9.3.6872.400
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: bdshare_firstime=1443768140949; uuid_tt_dd=5028529250430960147_20151002;
...省略

      

非常easy看出訪問的是我的部落格位址javascript:void(0),請求的方法是GET,因為是GET方法是以并沒有請求資料。

響應封包:

HTTP/1.1 200 OK                                                         //狀态行
Server: openresty                                                       //響應報頭
Date: Sun, 27 Mar 2016 08:26:54 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=20
Vary: Accept-Encoding
Cache-Control: private
X-Powered-By: PHP 5.4.28
Content-Encoding: gzip
                                                                        //不能省略的空格
28b5                                    
        }ysI   1ߡFsgl n- ]{^_ { 'z!     C ,  m# 0 !l   `  4x  ly .ݪ*  
  ڴzAt_Xl *  9'O  ɬ  '  ק   3  ^1a
...省略        

響應封包沒什麼可說的,接下來我們配置好手機網絡代理,訪問一個應用的界面

POST http://patientapi.shoujikanbing.com/api/common/getVersion HTTP/1.1       //請求行
Content-Length: 226                                                          //請求報頭
Content-Type: application/x-www-form-urlencoded
Host: patientapi.shoujikanbing.com
Connection: Keep-Alive
User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; MI NOTE LTE Build/KTU84P) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
Accept-Encoding: gzip
                                                             //不能省略的空格,以下是請求資料
clientversion=2_2.0.0&time=1459069342&appId=android&channel=hjwang&sessionId=0d1cee1f31926ffa8894c64804efa855101d56eb21caf5db5dcb9a4955b7fbc9&token=b191944d680145b5ed97f2f4ccf03058&deviceId=869436020220717&type=2&version=2.0.0      

從請求封包的請求行來看,請求的方法是POST,請求位址為​​http://patientapi.shoujikanbing.com/api/common/getVersion​​。非常顯然是擷取版本号資訊的接口。

HTTP/1.1 200 OK                                                              //狀态行
Server: nginx                                                               //響應報頭
Date: Sun, 27 Mar 2016 09:02:20 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Set-Cookie: sessionId=0d1cee1f31926ffa8894c64804efa855101d56eb21caf5db5dcb9a4955b7fbc9; expires=Mon, 28-Mar-2016 09:02:20 GMT; Max-Age=86400; path=/; domain=.shoujikanbing.com
Set-Cookie: PHPSESSID=0d1cee1f31926ffa8894c64804efa855101d56eb21caf5db5dcb9a4955b7fbc9; path=/; domain=.shoujikanbing.com
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Encoding: gzip
                                                   //不能省略的空格
17f                                                //實體封包編碼格式為gzip是以顯示在這裡的響應資料是亂碼
       mP N @     "E ?      

​ n m 1 w ( HL (1^ P nK E ѷ93'3gNLH 7P $c \ T 4a6 L:+ 1dY%$g h H + ...省略​

響應封包的實體採用的編碼格式為為gzip,是以在Fiddler軟體中顯示的是亂碼。

歡迎關注我的微信公衆号。第一時間獲得部落格更新提醒。以及很多其它成體系的Android相關原創技術幹貨。

掃一掃下方二維碼或者長按識别二維碼,就可以關注。