Android 你不得不學的HTTP相關知識

本章目錄

  • 一、http是怎麼定義的?
  • 二、http是怎麼工做的?
  • 三、報文是什麼?
  • 四、URL是什麼?
  • 五、RequestMethod請求方法有哪些?
  • 六、State Code狀態碼
  • 七、Header頭部
  • 八、Cache緩存
  • 九、http的發展史
  • 十、斷點續傳功能是怎麼實現的

本章結構圖

一、http是怎麼定義的?

1.一、超文本傳輸協議;

超文本傳輸協議(英語:HyperText Transfer Protocol,縮寫:HTTP)是一種用於分佈式、協做式和超媒體信息系統的應用層協議。HTTP是萬維網的數據通訊的基礎。html

設計HTTP最初的目的是爲了提供一種發佈和接收HTML頁面的方法。經過HTTP或者HTTPS協議請求的資源由統一資源標識符(Uniform Resource Identifiers,URI)來標識。前端

1.二、http在網絡中的分層;

最開始的網絡分層是分了有七層,以下;java

OSI模型:linux

後來因爲最上面三層(應用層、表示層和會話層)在TCP/IP組中是一個應用層,就合併到應用層了;git

TCP/IP組模型:github

而HTTP在網絡分層中是屬於應用層的協議;web

二、http是怎麼工做的?

http的工做方式一般是由客戶端和服務端協同完成的;數據庫

一般,由客戶端發起一個請求,建立一個到服務器指定端口(默認是80)的TCP連接,服務器則在這個端口監聽客戶端的請求,當接收到請求後,會根據客戶端的請求,返回對應的內容,好比html文本,圖片之類的,而且返回對應的狀態碼來告訴客戶端請求的狀態是否成功;json

三、報文是什麼?

3.一、http的報文是什麼?

HTTP報文是在HTTP應用程序之間發送的數據塊。跨域

將http比喻成快遞,那麼http報文就是包裹的快遞單,包含來姓名,地址,郵政編碼,表示我這個快遞要寄到哪裏去,而快遞中心收到這個快遞後,就會經過這個快遞單,來判斷這個包裹要寄送到哪裏去,而這個信息就是經過快遞單來獲取的;

那麼一樣http報文也是相似的道理,客戶端發送一個請求,帶上報文,服務端接收到請求後,解析這個報文,就知道客戶端須要獲取什麼東西來;

而服務端想客戶端返回內容時,也會帶上報文,表示我返回的內容是什麼,方便客戶端經過報文來解析數據,並處理的流程;

3.二、http報文的格式

http報文分爲請求報文和相應報文;

  • 請求報文:客戶端向服務器發送的報文;
  • 相應報文:服務端向客戶端發送的報文;

請求報文的格式:

由請求行,請求頭,空行,請求數據這四部分組成

舉例:請求百度的地址,打開瀏覽器的調試功能,查看請求報文;

響應報文的格式:

由狀態行,請求頭,空行,請求數據這四部分組成

舉例:一樣經過瀏覽器查看百度頁面的響應報文;

四、URL是什麼?

4.一、URL是怎麼定義的?

URL,全稱:Uniform Resource Locator 譯名:統一資源定位符,用於準確描述Internet上某一資源的地址;

咱們訪問的網頁都是有地址的,而地址一般指向某個服務器上的資源;

4.二、URL的格式是怎樣的?

URL的格式是由協議類型(http,https等),服務器地址(host),端口號(port),路徑(path)這幾部分組成的;

好比百度的地址:www.baidu.com/;

格式以下:http://host[:port][/path]

  • 協議類型:表示使用哪一種網絡協議來進行網絡請求,好比HTTP,HTTPS;
  • 服務器地址:表示主機,或者域名,或者IP地址;
  • 端口號:若是沒有指定的話,默認爲80;
  • 路徑:表示指定請求資源的URL,默認會帶上「/」,通常都是瀏覽器給咱們加上的;

五、RequestMethod請求方法有哪些?

5.一、請求方法

HTTP請求的方法有不少,以下:

  • GET:使用GET的請求用於從服務器獲取數據;

  • HEAD:和GET請求類似,可是沒有響應體;

  • POST方法:用於將內容提交到服務器,一般用於修改或者刪除服務器上的資源;

  • PUT方法:一般用於修改服務器上的數據;

  • DELETE方法:刪除服務器指定的資源;

  • CONNECT方法:創建一個到由目標資源標識的服務器的隧道,用於代理服務器;

  • OPTIONS方法:用於描述目標資源的通訊選項,一般用於跨域請求;

  • TRACE方法:沿着到目標資源的路徑執行一個消息環回測試,用於追蹤請求;

5.二、GET和POST請求的區別

咱們最經常使用的的請求方法,基本上就是GET和POST請求了,那麼咱們來看一下他們的區別吧;

一般在瀏覽器上輸入一個地址進行請求,通常都是經過GET請求方式,而POST請求通常用於提交內容,將須要提交給服務器的參數放到body裏面,進行請求;

來看看w3school列舉的差別點:

疑問:
1,安全性:

GET的請求在瀏覽器上是能夠看到請求的參數的,基本上來講沒有安全性可言;

而POST請求在瀏覽器上看不到請求參數,是否是表示就是安全的呢?

並非,別人能夠經過抓包的方式來獲取到你的請求參數,因此並非安全的,要想安全的傳輸只能經過有加密方式的HTTPS請求;

2,POST方法是否會產生兩個TCP數據包?

答案是:不必定;

這個不是必然會產生兩個TCP數據包,而是看瀏覽器是否作了發送兩次TCP數據包的處理,若是有作處理的話就會發送兩次TCP數據包;

網上已經有文章驗證過了,我這裏就再也不多說了,經驗證的結果爲:Chrome和Safari瀏覽器會發送兩次TCP數據包,而Firefox瀏覽器只發送了一次;

詳情請參考:據說『99% 的人都理解錯了 HTTP 中 GET 與 POST 的區別』??

3,URL過長會致使什麼問題?

咱們先用postman來模擬一下看看,弄一個超長的URL,請求一下看會不會報錯;

從圖片上能夠看出,postman直接返回了414 Request-URL Too Long,表示當前URL過長了;

用瀏覽器請求返回的錯誤信息也是同樣:

那麼這裏是否會有疑問,爲何URL過長會報錯? 是服務器處理不了,仍是postman處理不了? 仍是http協議規定的URL不能超過多長呢?

查看RFC的http的相關文檔(RFC 2616 - HTTP/1.1)發現裏面的一段話,以下:

The HTTP protocol does not place any a priori limit on the length of a URI. Servers MUST be able to handle the URI of any resource they serve, and SHOULD be able to handle URIs of unbounded length if they provide GET-based forms that could generate such URIs. A server SHOULD return 414 (Request-URI Too Long) status if a URI is longer than the server can handle (see section 10.4.15).

翻譯過來的意思就是:

HTTP協議沒有對長度進行任何限制,服務器必須可以處理其任何資源的URI服務,而且應該可以處理長度不受限制的URI,若是URI較長,則應返回414(請求URI太長)狀態超出服務器的處理能力;

看到這裏,咱們就明白了,http協議並無限制URL的長度,對URL長度作處理的,只有服務器或者瀏覽器,因此URL過長致使的報錯是由服務器或者瀏覽器處理的;

4,GET方法能夠帶Body嗎?

答案是:能夠的!

爲何GET方法能夠帶Body嗎?不是說GET方法是經過URL來取資源的嗎?

來看一下RFC的協議中,對於GET方法的定義:

The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.

翻譯過來的意思就是GET方法是經過URL來檢索服務器上的信息,並無說不能帶上Body;

那麼到這裏你是否就有疑惑了? 他沒說不就表明他能夠帶上Body來請求啊;別急,咱們繼續分析;

再來看另一份RFC協議對於GET請求帶Body的解釋:

A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.

翻譯過來的意思就是帶上Body的GET方法,可能會致使拒絕請求,有多是服務器拒絕了,也有多是瀏覽器或者框架拒絕請求;

結論:GET方法是能夠帶上Body請求的,可是可能會發生拒絕請求的錯誤,或者一些其餘的錯誤出現;

那麼對於GET方法帶上Body的測試這裏就很少說了,感興趣的請參考:誰說 HTTP GET 就不能經過 Body 來發送數據呢?

六、State Code狀態碼

6.一、狀態碼是什麼?

狀態碼是客戶端向服務端請求後,服務端會返回一個數字來告訴端側請求的狀態,好比200,表示請求成功了,好比404,客戶端錯誤了;這樣客戶端再拿到狀態碼以後再作相應的處理,好比是否重試,好比展現錯誤頁面,好比提示用戶操做不當之類的;

6.一、狀態碼有哪些?

看一下菜鳥教程對於狀態碼的定義:

如圖所示,http狀態碼主要分爲5種類型,分別爲1xx,2xx,3xx,4xx,5xx等開頭的狀態碼;

每個狀態碼以x開頭的均可歸類爲某一種類型的狀態;好比200(請求成功),404(客戶端錯誤)等;

狀態碼的種類有不少,這裏就不一一介紹了;

七、Header頭部

7.一、Header是用來幹嗎的?

Header實際上是一個鍵值對,是屬於元數據,用於告訴服務器,我要取什麼樣的數據或者我要作什麼樣的操做;

好比:Accept: text/plain,表示客戶端能接受文本數據的返回;

除了先有的一些標準的請求頭,咱們還能夠自定義請求頭,好比:user:"張三",表示我要傳 "張三"的Header到服務器,服務器再作相應的處理;

7.二、Header有哪些?

HTTP頭字段按照實際用途能夠分爲四種類型,分別爲通用頭,請求頭,響應頭和實體頭這四種;

  • 通用頭:是客戶端和服務器均可以使用的頭部,能夠在客戶端、服務器和其餘應用程序之間提供一些很是有用的通用功能,如Date頭部;
  • 請求頭:是請求報文特有的,它們爲服務器提供了一些額外信息,好比客戶端但願接收什麼類型的數據,如Accept頭部;
  • 響應頭:便於客戶端提供信息,好比,客服端在與哪一種類型的服務器進行交互,如Server頭部;
  • 實體頭:指的是用於應對實體主體部分的頭部,好比,能夠用實體頭部來講明實體主體部分的數據類型,如Content-Type頭部;

7.三、常見的Header的類型有哪些?

1,Host

客戶端指定本身想訪問的WEB服務器的域名/IP 地址和端口號;

2,Content-Type

用於指定請求體的類型,主要有四種;

(1)text/html:用於告訴服務器須要響應的類型爲文本數據類型;

(2)x-www-form-urlencoded:表單類型,用於web頁面純文本表單提交數據到服務器,好比註冊頁面數據的提交;

(3)multitype/form-data:用於web頁面帶二進制文件的表單提交方式,好比修改用戶頭像,會上傳圖片到服務器;

(4)application/json , image/jpeg , application/zip ...:提交單項內容到服務器,好比提交json,提交image,提交zip包到服務器;

3,Content-Length

用於指定響應體的長度,表示我此次請求須要返回多少字節的內容,多用於分塊傳輸;

4,User-Agent

用於向服務端代表身份信息,表示我是來自手機客戶端的請求,仍是來自某個瀏覽器的請求;

5,Range

表示想從服務器取哪部分的內容,好比byte:start-end;用於多線程下載或者斷點續傳;

6,Accept

告訴服務器客戶端能接受什麼類型的數據,好比text/html;

7,Accept-Charset

告訴服務器客戶端能接受的的字符集,好比utf-8;

8,Accept-Encoding

告訴服務器客戶端能接受的壓縮編碼類型,如zip;

9,Content-Encoding

服務器告訴客戶端本身使用了什麼壓縮方法,如gzip,deflate等;

HTTP的Header類型是在是太多了,這裏就不一一介紹了,感興趣的請參考: 「Android系列之網絡(二)----HTTP請求頭與響應頭

八、Cache緩存

8.一、http爲何須要緩存?

1,經過網絡獲取內容,會受速度影響而且開銷很大,須要在客戶端和服務器之間創建通信,而後經過傳包的方式來進行通信,受網絡速度影響,有可能會響應比較慢,致使前端的展現體驗很差;

2,減小開銷,若是每一次請求都從服務器取的話,那麼服務器將會面臨巨大的壓力,有可能會掛掉,致使訪問不了;

3,使用緩存還能夠減小網絡帶寬的佔用,過多的請求會致使網絡阻塞,從而響應速度也變慢;

4,減小無心義的重複請求,好比某個頁面的數據,運營一天才會去修改一次,可是我每次進來這個頁面都去從服務器請求數據,這樣是沒有意義的,只會致使資源的浪費;

因此使用緩存能夠大大的提高響應速度,下降服務器壓力,減小帶寬的佔用,所以HTTP的緩存是相當重要的;

8.二、http的緩存機制是什麼?

1,經過 ETag 驗證緩存的響應

(1)ETag是什麼?

ETag 本質上是一個header,也被稱爲驗證令牌,是由服務器根據根據文件生成的hash值或者其餘的某個值;

(2)驗證令牌的誕生旨在解決什麼問題?

假如咱們本地的數據是有緩存時效的,當咱們從本地取數據的時候,發現緩存時效過時了,這時候就會去服務器那邊取數據,可是此時從服務器取回來的數據和本地的數據是同樣的,沒有什麼變化,只是本地的緩存時效過時了,這時候從服務器取回來的數據就沒有意義了,還浪費了請求所消耗的資源;

那麼驗證令牌就是爲了解決這類問題而誕生的;

(3)驗證令牌是怎麼解決這類問題的?

前面說了,驗證令牌本質上是一個header,咱們去服務器取數據的時候會帶上這個header,好比 ETag:"xxxxxx"; 服務器收到這個header以後,就會去作驗證,若是驗證對比了令牌後發現,沒有變化,則返回「304 Not Modified」響應,告訴瀏覽器緩存重點數據沒有發生什麼變化,能夠繼續使用,那麼咱們接受到響應後,更新本地的緩存時效,進而繼續使用緩存;

借用官方的圖:

image.png

2,Cache-Control 緩存控制

(1)Cache-Control是用來幹嗎的?

Cache-Control是用來定義緩存策略的,好比定義某個資源在什麼場景下,緩存多長的時間,本質上是一個header;

Cache-Control是在 HTTP/1.1 規範中定義的;

(2)Cache-Control怎麼定義緩存策略?

Cache-Control經過header定義的緩存指令來實現緩存策略,好比Cache-Control:max-age = 180;

(3)緩存指令有哪些?

請求指令

  • no-cache:會先經過ETag驗證令牌和服務器進行通信,判斷服務器的數據是否有修改過,若是有修改過,則使用服務器返回的新的數據,不然的話就取緩存,使用這個指令會和服務器進行一次通信;

  • no-store:指令爲"no-store"的狀況下,一概不進行緩存,都是從服務器取數據,通常用於須要安全的場景或者須要實時刷新的場景;

  • max-age:表示當前請求的響應體的有效時間爲多長,超過了這個時效則從服務器取數據;

  • public:表示能夠被任何中間者(代理服務器,cdn等)或者瀏覽器緩存數據,一般狀況下,public並非必須的指令,有其餘指令(好比max-age)表示了該請求能夠被緩存;

  • private:表示不能夠被任何中間者(代理服務器,cdn等)緩存數據,可是瀏覽器能夠緩存該指令的數據;

三、Expires緩存頭

Expires相應頭包含日期和時間,下次請求時,會將本地時間和這個時間作比較,若是若是緩存有效,則取緩存,可是因爲本地時間和服務器時間不一樣步,用這個來判斷緩存時效會存在不許的問題,所以在HTTP1.1以後更多的是使用Cache-Control 指令,更加靈活;

四、Cache-Control在okhttp中的體現

final CacheControl.Builder builder = new CacheControl.Builder();
            builder.noCache();//不使用緩存,所有走網絡
            builder.noStore();//不使用緩存,也不存儲緩存
            builder.maxAge(10, TimeUnit.MILLISECONDS);//指示客戶機能夠接收生存期不大於指定時間的響應。
            CacheControl cache = builder.build();//cacheControl
複製代碼

九、http的發展史

9.一、HTTP 0.9

萬維網協會(World Wide Web Consortium,W3C)和互聯網工程任務組(IETF)在1991年的時候制定了 HTTP 0.9 標準,那時候只支持GET方法請求;

9.二、HTTP 1.0

從單一的GET方法請求,新增了POST請求,支持發送任何格式的內容,包括文本,視頻,音樂,和二進制文件;

請求體和返回體的格式也變了,新增了頭信息(Header),狀態碼(status code),多字符集支持、多部分發送(multi-part type)、權限(authorization)、緩存(cache)、內容編碼(content encoding)等功能;

缺點

(1)鏈接沒法複用,瀏覽器和服務器只能創建短暫的TCP鏈接,當請求完畢以後,就關閉該TCP鏈接;若是須要從新請求,則須要從新創建TCP鏈接,會致使資源的浪費,以及響應的時間;

(2)Head-Of-Line Blocking(HOLB,隊頭阻塞),在TCP鏈接中,請求是有序的,只有當服務器處理完前一個請求後,纔會處理下一個請求,若是前一個請求速度較慢,就會形成後續請求阻塞等待的狀況出現;

9.三、HTTP 1.1

HTTP 1.1是當前最流行的http版本;

優化點
(1)緩存:在 HTTP 1.0 中主要使用 header 裏的 If-Modified-Since,Expires 來作爲緩存判斷的標準,HTTP 1.1則引入了更多的緩存控制策略例如 Entity tag,If-Unmodified-Since等更多可供選擇的緩存頭來控制緩存策略。

(2)帶寬的優化:新增了range頭字段,用於分塊傳輸,容許請求當前文件的部份內容,這樣能夠大大減小網絡帶寬的佔用;

(3)新增了24 個錯誤狀態響應碼

(4)長連接:頭字段新增了Connection:keep-alive,表示能夠複用一部分連接,在tcp鏈接上能夠傳達多個請求,以此來減小創建和鏈接帶來的消耗;

(5)增長管線化技術(pipelining),在當前請求尚未返回時,能夠發送下一個請求到服務器,以此來下降請求時間;

缺點

(1)長連接:雖然加入長連接能夠減小創建和鏈接帶來的消耗,可是不一樣的域名的連接不能複用,只能從新建立長連接,會耗費資源,而且給服務器帶來巨大的壓力;

(2)在header中攜帶請求的數據量過大,形成流量的浪費,若是每次請求header的內容不變,可是header攜帶的數據量又很大的狀況下,就會形成資源的浪費;

(3)HTTP 1.1雖然引入了pipelining來解決隊頭阻塞問題(Head-Of-Line Blocking),即瀏覽器能夠同時發送多個請求給服務器,沒必要等到上一個請求返回以後再進行請求,可是服務器的處理是等處理完當前請求的響應以後,纔會去處理下一個請求的響應,即便當前不少請求都已經處理完了,服務器仍是得根據請求的順序來進行響應;

所以它不是真正的多請求協議,可是是一個很好的改進;

9.四、HTTP 2.0

HTTP2.0基於谷歌開發的SPDY協議,而HTTP 2.0相對於HTTP 1.1帶來了什麼新的改進呢?

優化點:

(1)多路複用:對於HTTP1.1中,若是當前有多個請求,請求的發送都是串行執行的,對於寬帶的利用效率不高,可是在HTTP 2.0中,多個請求能夠並行請求,大大的提高了寬帶的利用率;

(2)Header壓縮:使用首部表來跟蹤和存儲以前發送的鍵值對,對於相同的內容,不會再每次請求和響應時發送。

(3)數據優先級:因爲請求能夠併發發送給服務器,可是服務器仍是遵循先進先出的規則來處理請求,可是在HTTP 2.0中能夠設置當前請求的優先級,這樣服務器在處理請求的響應時,會優先返回優先級較高的請求;

(4)服務端推送:對於請求,通常都是瀏覽器或者客戶端發送給服務器,服務器處理以後再返回,可是在HTTP 2.0中服務器能夠推送相關文件給客戶端,客戶端再進行相應的處理,而沒必要等客戶端發送請求以後再返回給客戶端;

十、斷點續傳功能是怎麼實現的?

10.一、原理

原理很簡單,就是從中止下載的地方繼續下載,好比我下載了10兆,文件總共有20兆,此時的斷點下載就是從10兆開始進行續傳,繼續下載的;

10.二、核心

經過http的Range頭字段來實現的,Range頭字段支持從服務器或者指定內容範圍大小的文件,好比我想要或者某個文件的前1024字節的數據,那麼我只須要傳 Range: bytes=0-1024 (0到1024字節的數據),這樣就能夠從服務器獲取到對於字節的數據了;

10.三、好處

斷點續傳的好處就是傳輸效率高,好比下載一個文件,在傳輸過程當中受網絡影響中斷了,這時不須要在開頭從新下載,而是在中止的地方繼續下載;

斷點續傳還能夠經過多線程來提升效率,好比下載一個文件,我能夠開10個線程或者20個線程來分段下載文件,這樣能夠大大的提升下載速度,像迅雷或者百度雲大多都是這種原理,只是更加複雜;至於最多能開多少線程進行下載, 要看當前客戶端的性能;

10.三、客戶端的實現

數據庫:用於存儲斷點下載的其實位置;

多線程:用於加快下載速度;

RandomAccessFile類:Java提供的對文件內容的訪問,既能夠讀文件也能夠寫文件,能夠訪問文件的任意位置適用於由大小已知的記錄組成的文件;

下面從一張圖來看看具體實現:

image.png

參考&感謝

關於我

兄dei,若是個人文章對你有幫助的話,請幫我點個贊吧️,也能夠關注一下個人Github博客;

相關文章
相關標籤/搜索