1. 程式人生 > >TCP/IP協議,HTTP協議--面試必備

TCP/IP協議,HTTP協議--面試必備

經常面試被問到什麼是http協議,什麼是TCP協議,而且每次都弄不清楚,是時候記錄一下了

一、什麼是http協議?

如果讀者對計算機網路的體系結構比較瞭解的話應該清楚,IP協議位於網路層,TCP/UDP協議位於傳輸層,HTTP位於應用層,如下圖:

網路體系結構
說明:

  • TCP是傳輸層協議,主要解決資料如何在網路中傳輸;HTTP協議是應用層協議,是TCP協議的上層協議,主要用於客戶端與伺服器 之間的資料傳輸
  • socket是對TCP協議的封裝,是一個呼叫介面。

二、怎麼發起HTTP請求?

其實發起一個HTTP請求就是建立一個socket連線,是不過HTTP請求是無狀態且短連結的協議
瀏覽器在建立socket連線之前,先根據DNS伺服器去把域名解析成對應的IP地址,將IP地址和預設的80埠(https請求和http類似,只不過他用的是443埠和證書)與伺服器建立一個socket連結。

我們利用程式碼來模擬一下客戶端的請求過程,具體程式碼:

URLConnection urlConnection = new URL("http://www.baidu.com").openConnection();
        urlConnection.connect();
        Map<String, List<String>> map = urlConnection.getHeaderFields();
        for(String key:map.keySet()){
            System.out.println(key+
":"+map.get(key)); }

深入分析URLConnection程式碼發現,它的底層也是使用socket實現,sun.net.NetworkClient的內部實現:

protected Socket doConnect (String server, int port)
 152     throws IOException, UnknownHostException {
 153         Socket s;
 154         if (proxy != null) {
 155             if (proxy.type() == Proxy.Type.SOCKS) {
 156
s = AccessController.doPrivileged( 157 new PrivilegedAction<Socket>() { 158 public Socket run() { 159 return new Socket(proxy); 160 }}); 161 } else if (proxy.type() == Proxy.Type.DIRECT) { 162 s = createSocket(); 163 } else { 164 // Still connecting through a proxy 165 // server & port will be the proxy address and port 166 s = new Socket(Proxy.NO_PROXY); 167 } 168 } else 169 s = createSocket(); 170 // Instance specific timeouts do have priority, that means 171 // connectTimeout & readTimeout (-1 means not set) 172 // Then global default timeouts 173 // Then no timeout. 174 if (connectTimeout >= 0) { 175 s.connect(new InetSocketAddress(server, port), connectTimeout); 176 } else { 177 if (defaultConnectTimeout > 0) { 178 s.connect(new InetSocketAddress(server, port), defaultConnectTimeout); 179 } else { 180 s.connect(new InetSocketAddress(server, port)); 181 } 182 } 183 if (readTimeout >= 0) 184 s.setSoTimeout(readTimeout); 185 else if (defaultSoTimeout > 0) { 186 s.setSoTimeout(defaultSoTimeout); 187 } 188 return s; 189 } 190

三、瀏覽器怎麼解析HTTP請求?

我們也可以通過curl/charles/wireshark來進行抓包分析HTTP資料包,下面我通過curl來檢視http的請求頭資訊,命令如下:
HTTP 請求由三部分組成:請求行、 請求頭和請求正文。

curl -v http://www.baidu.com

請求頭資訊:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Cache-Control:max-age=0
Connection:keep-alive
Cookie:BIDUPSID=FAB2DD0A535CCE85F60B0E747EDD2F80; PSTM=1493346210; BAIDUID=A132C53C54C0BD857558B3C9A0BE6888:FG=1; BDUSS=VxWWlZN2p3Z3I5a3hyejdvQ0ppVmxXcmNDcFhyckozT2t4RE5HRXRxall6UzlaSVFBQUFBJCQAAAAAAAAAAAEAAAAkHEsRenp4MDEwMTAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANhACFnYQAhZMX; BDSFRCVID=krPsJeC62xGbH8QZbUZhu8KOK2KfnEnTH6aomPIViliOVFyXv0lyEG0PqU8g0Kub5QsaogKK0mOTHvbP; H_BDCLCKID_SF=tb4q_I_aJCvbfP0kj502e5OQDa0jJI62aKDs0U5c-hcqEIL4jh85jIuuWmcPBUoaJnI8-bCa2R6RMxbSj4Qo3-INyx6UKf7bWnvnWnTCyp5nhMJI3j7JDMP0qtOkKxny523ion6vQpn-8UtuD6-bDj5WeHDs-bbfHjrtBRRV-bnHDR365DTjhPrMMp5TbMT-0bFHXp3tWInGoRoaW47heMPgyN5iKt64aHn7_JjOaxJzSRT1Mfn4QRFR5G3QhxQxtNRD-CnjtpvhHC5hKPQobUPUDMc9LUvqKH4E3-oJqCKhMDLm3H; BDRCVFR[S4-dAuiWMmn]=I67x6TjHwwYf0; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; BDRCVFR[dG2JNJb_ajR]=mk3SLVN4HKm; BD_CK_SAM=1; PSINO=2; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BD_HOME=1; H_PS_PSSID=1441_19033_21111_17001_19897_21670_22582; BD_UPN=123253; sugstore=1
Host:www.baidu.com
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36

常見請求頭

  • GET方法是預設的HTTP請求方法,例如當我們通過在瀏覽器的位址列中直接輸入網址的方式去訪問網頁的時候,瀏覽器採用的就是 GET 方法向伺服器獲取資源。
  • Host(傳送請求時,該報頭域是必需的)
    Host請求報頭域主要用於指定被請求資源的Internet主機和埠號,它通常從HTTP URL中提取出來的。

  • Accept:瀏覽器可以接受的媒體型別(MIME型別),
    例如: Accept: text/html 代表瀏覽器可以接受伺服器回發的型別為 text/html 也就是我們常說的html文件, 如果伺服器無法返回text/html型別的資料,伺服器應該返回一個406錯誤(non acceptable)。
    萬用字元 * 代表任意型別。例如 Accept: / 代表瀏覽器可以處理所有型別,(一般瀏覽器發給伺服器都是發這個)

  • User-Agent:告訴HTTP伺服器, 客戶端使用的作業系統和瀏覽器的名稱和版本.
    我們上網登陸論壇的時候,往往會看到一些歡迎資訊,其中列出了你的作業系統的名稱和版本,你所使用的瀏覽器的名稱和版本,這往往讓很多人感到很神奇,實際上, 伺服器應用程式就是從User-Agent這個請求報頭域中獲取到這些資訊User-Agent請求報頭域允許客戶端將它的作業系統、瀏覽器和其它屬性告訴伺服器

  • Accept-Encoding:瀏覽器申明自己接收的編碼方法,通常指定壓縮方法,是否支援壓縮,支援什麼壓縮方法(gzip,deflate),(注意:這不是隻字元編碼);
    例如: Accept-Encoding: gzip, deflate。Server能夠向支援gzip/deflate的瀏覽器返回經gzip或者deflate編碼的HTML頁面。 許多情形下這可以減少5到10倍的下載時間,也節省頻寬。

  • Accept-Language: 瀏覽器申明自己接收的語言。
    語言跟字符集的區別:中文是語言,中文有多種字符集,比如big5,gb2312,gbk等等;
    例如: Accept-Language:zh-cn 。如果請求訊息中沒有設定這個報頭域,伺服器假定客戶端對各種語言都可以接受。

  • Connection:表示是否需要持久連線。
    如果伺服器看到這裡的值為“Keep-Alive”,或者看到請求使用的是HTTP 1.1(HTTP 1.1預設進行持久連線),它就可以利用持久連線的優點,當頁面包含多個元素時(例如Applet,圖片),顯著地減少下載所需要的時間。要實現這一點,伺服器需要在應答中傳送一個Content-Length頭,最簡單的實現方法是:先把內容寫入 ByteArrayOutputStream,然後在正式寫出內容之前計算它的大小;
    例如: Connection: keep-alive 當一個網頁開啟完成後,客戶端和伺服器之間用於傳輸HTTP資料的TCP連線不會關閉,如果客戶端再次訪問這個伺服器上的 網頁,會繼續使用這一條已經建立的連線 . Connection: close 代表一個Request完成後,客戶端和伺服器之間用於傳輸HTTP資料的TCP連線會關閉, 當客戶端再次傳送Request,需要重新建立TCP連線
curl -I http://www.baidu.com

響應頭資訊:

Accept-Ranges:[bytes]
null:[HTTP/1.1 200 OK]
Cache-Control:[private, no-cache, no-store, proxy-revalidate, no-transform]
Server:[bfe/1.0.8.18]
ETag:["588604c4-94d"]
Connection:[Keep-Alive]
Set-Cookie:[BDORZ=27315; max-age=86400; domain=.baidu.com; path=/]
Pragma:[no-cache]
Last-Modified:[Mon, 23 Jan 2017 13:27:32 GMT]
Content-Length:[2381]
Date:[Sat, 10 Jun 2017 03:38:14 GMT]
Content-Type:[text/html]

響應頭常用資訊:

  • 狀態行:狀態行由協議版本、數字形式的狀態程式碼,及相應的狀態描述組成,各元素之間以空格分隔,結尾時回車換行符,例如:HTTP/1.1 200 OK
  • Expires:瀏覽器會在指定過期時間內使用本地快取,指明應該在什麼時候認為文件已經過期,從而不再快取它。
  • Set-Cookie: 非常重要的header, 用於把cookie 傳送到客戶端瀏覽器, 每一個寫入cookie都會生成一個Set-Cookie.
  • Entity實體頭域:實體內容的屬性,包括實體資訊型別,長度,壓縮方法,最後一次修改時間,資料有效性等。
  • ETag:和If-None-Match 配合使用。
  • Last-Modified: 用於指示資源的最後修改日期和時間。
  • If-None-Match: If-None-Match和ETag一起工作,工作原理是在HTTP Response中新增ETag資訊。 當用戶再次請求該資源時,將在HTTP Request 中加入If-None-Match資訊(ETag的值)。如果伺服器驗證資源的ETag沒有改變(該資源沒有更新),將返回一個304狀態告訴客戶端使用本地快取檔案。否則將返回200狀態和新的資源和Etag. 使用這樣的機制將提高網站的效能
  • Server:指明HTTP伺服器的軟體資訊
  • Pragma:防止頁面被快取, 在HTTP/1.1版本中,它和Cache-Control:no-cache作用一模一樣 ,Pargma只有一個用法, 例如: Pragma: no-cache
    Cache-Control: 這個是非常重要的規則。 這個用來指定Response-Request遵循的快取機制。各個指令含義如下
    Cache-Control:Public 可以被任何快取所快取()
    Cache-Control:Private 內容只快取到私有快取中
    Cache-Control:no-cache 所有內容都不會被快取
  • Content-Length:指明實體正文的長度,以位元組方式儲存的十進位制數字來表示。在資料下行的過程中,Content-Length的方式要預先在伺服器中快取所有資料,然後所有資料再一股腦兒地發給客戶端。
  • Content-Encoding:文件的編碼(Encode)方法。一般是壓縮方式。

四、瀏覽器快取是什麼?

瀏覽器快取一般是前端工程師必須要掌握的,但是,我們作為後端開發也需要了解一下,畢竟技多不壓身。

它就是我們在開啟一個有快取的網頁時,瀏覽器會將其自動下載儲存到本地(副本)。我們一般通過ctrl+f5來強制重新整理本地快取。
Cache-Control:快取控制頭資訊,是關於瀏覽器快取的最重要的設定,不僅可以控制瀏覽器,還可以覆蓋其他設定(如Expires和Last-Modified)或代理伺服器。另外,由於瀏覽器的行為基本相同,這個屬性是處理跨瀏覽器快取問題的最有效的方法。
Pragma:與Cache-Control功能類似。Pragma屬於通用首部欄位,在客戶端上使用時,常規要求我們往html上加上這段meta元標籤,如:<meta http-equiv="Pragma" content="no-cache">用於告訴瀏覽器每次請求頁面時都不要讀快取,都得往伺服器發一次請求才行。
說明:僅有IE才能識別這段meta標籤含義;它不一定會在請求欄位加上Pragma,但的確會讓當前頁面每次都發新請求(僅限頁面,頁面上的資源則不受影響)。
Expires:
過期頭資訊,通常後面跟一個時間,超過這個時間快取內容將會失效。在客戶端上使用時,我照樣可以加上meta元標籤,如:
<meta http-equiv="expires" content="Sun, 04 Jun 2017 14:40:01 GMT">
說明:同樣也只有IE能夠識別,如果希望每次重新整理頁面都能發新請求,那麼可以把“content”裡的值寫為“-1”或“0”。Pragma欄位的優先順序會高於Pragma。
Last-Modified/ETag快取校驗欄位;用於判斷控制檔案是否有修改.