簡述HTTP協議

Aaron發表於2019-06-30

身為開發人員除了應該對我們所寫的專案需求要了解,以及基本的語言知識,對於HTTP協議也是應該瞭解一下的,因為這些東西與我們是密不可分的,每天都在和HTTP打交道然而卻不知道它到底是什麼?這樣說出去是不是很可悲?簡直可歌可泣有沒有...

http協議:HTTP是一個簡單的請求-響應協議,它通常執行在TCP之上。它指定了客戶端可能傳送給伺服器什麼樣的訊息以及得到什麼樣的響應。請求和響應訊息的頭以ASCII碼形式給出;而訊息內容則具有一個類似MIME的格式。這個簡單模型是早期Web成功的有功之臣,因為它使得開發和部署是那麼的直截了當。超文字傳輸協議(HTTP)是用於傳輸諸如HTML的超媒體文件的應用層協議。它被設計用於Web瀏覽器和Web伺服器之間的通訊,但它也可以用於其他目的。HTTP遵循經典的客戶端-服務端模型,客戶端開啟一個連線以發出請求,然後等待它收到伺服器端響應。 -- 百度百科

HTTP是無狀態協議,意味著伺服器不會在兩個請求之間保留任何資料(狀態)。在同一個連線中,兩個執行成功的請求之間是沒有關係的。這就帶來了一個問題,使用者沒有辦法在同一個網站中進行連續的互動,比如在一個電商網站裡,使用者把某個商品加入到購物車,切換一個頁面後再次新增了商品,這兩次新增商品的請求之間沒有關聯,瀏覽器無法知道使用者最終選擇了哪些商品。而使用HTTP的頭部擴充套件,HTTP Cookies就可以解決這個問題。把Cookies新增到頭部中,建立一個會話讓每次請求都能共享相同的上下文資訊,達成相同的狀態。通過上述得出結論,http特點是:無狀態,無連線,簡單快速。

HTTP互動流程

一個連線是由傳輸層來控制的,這從根本上不屬於HTTP的範圍。HTTP並不需要其底層的傳輸層協議是面向連線的,只需要它是可靠的,或不丟失訊息的(至少返回錯誤)。在網際網路中,有兩個最常用的傳輸層協議:TCP是可靠的,而UDP不是。因此,HTTP依賴於面向連線的TCP進行訊息傳遞,但連線並不是必須的。

  • TCP:面向連線(如打電話要先撥號建立連線)
  • UDP:是無連線的,即傳送資料之前不需要建立連線

關於TCPUDP這裡不做多餘贅述,如果想要深入瞭解兩者之間的優缺點以及區別的話,有時間再詳細的介紹一下。

其實HTTP互動流程就是基於TCP連線進行訊息傳遞的,然而這個連線可有可無,具體互動流程如下圖:

o_http.png

結合上圖詳細說明經歷的過程:

  1. 開啟一個TCP連線:TCP連線被用來傳送一條或多條請求,以及接受響應訊息。客戶端可能開啟一條新的連線,或重用一個已經存在的連線,或者也可能開幾個新的TCP連線連向服務端
  2. 傳送一個HTTP報文:HTTP報文(在HTTP/2之前)是語義可讀的。在HTTP/2中,這些簡單的訊息被封裝在了幀中,這使得報文不能被直接讀取,但是原理仍是相同的
  3. 讀取服務端返回的報文資訊,伺服器端接收到請求後,進行處理,然後將處理結果響應客戶端(HTTP協議)
  4. 關閉連線或者為後續請求重用連線,關閉客戶端和伺服器端的連線(HTTP1.1後不會立即關閉)

HTTP流水線啟動時,後續請求都可以不用等待第一個請求的成功響應就被髮送。然而HTTP流水線已被證明很難在現有的網路中實現,因為現有網路中有很多老舊的軟體與現代版本的軟體共存。因此,HTTP流水線已被在有多請求下表現得更穩健的HTTP/2的幀所取代。

HTTP報文

Linux系統下有一個curl指令可以通過這個命令來觀測一下HTTP的請求過程。

curl -v https://segmentfault.com/

輸入完之後回車就會看到下面這些資訊:

o_http.jpg

圖中>開始的是客服端傳送給服務端的資訊,以<開始的為服務端返回給客戶端的一些資訊。當客戶端發起一個Ajax請求時,瀏覽器會攜帶一些資訊傳送給服務端,HTTP請求頭提供了關於請求,響應或者其他的傳送實體的資訊。請求報文分為以下幾個部分:

  1. General(請求行)
  2. Response Headers(請求頭)
  3. Request Headers(響應頭)

這三個部分分別承載了服務端以及客戶端所需要的資訊,在瀏覽器中種NetWork中可以檢視到其資訊內容,接下來就一一介紹一下:

General

這部分主要提供的是一些公用的請求頭資訊:

Request URL: https://segmentfault.com/search?q=search
Request Method: GET
Status Code: 200 
Remote Address: 112.126.83.219:443
Referrer Policy: no-referrer-when-downgrade
  • Request URL:請求地址
  • Request Method:請求方式
  • Status Code:狀態碼
  • Remote Address:請求的遠端地址
  • Referrer Policy: 過濾 Referrer 報頭內容

上述資訊表明,客戶端向伺服器傳送一個http請求,其請求地址為https://segmentfault.com/search?q=search,使用GET方式發起這個請求,請求返回狀態為200,連線的遠端地址為112.126.83.219:443,過濾報頭採用的是不傳遞Referrer

向前面幾個應該都比較熟悉也通俗易懂,當看到的這的時候心裡有一些些的小疑惑Remote Address是什麼?Referrer Policy過濾報頭的規則有哪些?

Remote Address

關於Remote Address遠端連線地址,Remote Address代表客戶端的IP,但它的值不是由客戶端提供的,而是服務端根據客戶端的IP指定的,當你的瀏覽器訪問某個網站時,假設中間沒有任何代理,那麼網站的web伺服器(Nginx,Apache等)就會把Remote Address設為你的機器IP,如果你用了某個代理,那麼你的瀏覽器會先訪問這個代理,然後再由這個代理轉發到網站,這樣web伺服器就會把Remote Address設為這臺代理機器的IP。以至於後面的443埠,也簡單的看了一下,443埠即網頁瀏覽埠,主要是用於HTTPS服務,是提供加密和通過安全埠傳輸的另一種HTTP。在一些對安全性要求較高的網站,比如銀行、證券、購物等,都採用HTTPS服務,這樣在這些網站上的交換資訊,其他人抓包獲取到的是加密資料,保證了交易的安全性。我也沒有做深入的瞭解,大概就是這個樣子吧。

Referrer Policy

Referrer-Policy的作用就是為了控制請求頭中referrer的內容,目前是一個候選標準,不過已經有部分瀏覽器支援該標準。目前Referrer-Policy只包含以下幾種值:

解釋
no-referrer 不顯示referrer的任何資訊在請求頭中。
no-referrer-when-downgrade 這是預設值。當從https網站跳轉到http網站或者請求其資源時(安全降級HTTPS→HTTP),不顯示referrer的資訊,其他情況(安全同級HTTPS→HTTPS,或者HTTP→HTTP)則在referrer中顯示完整的源網站的URL資訊。
same-origin 表示瀏覽器只會顯示referrer資訊給同源網站,並且是完整的URL資訊。所謂同源網站,是協議、域名、埠都相同的網站。
origin 表示瀏覽器在referrer欄位中只顯示源網站的源地址(即協議、域名、埠),而不包括完整的路徑。
strict-origin 該策略更為安全些,和origin策略相似,只是不允許referrer資訊顯示在從https網站到http網站的請求中(安全降級)。
origin-when-cross-origin 當發請求給同源網站時,瀏覽器會在referrer中顯示完整的URL資訊,發個非同源網站時,則只顯示源地址(協議、域名、埠)
strict-origin-when-cross-origin 和origin-when-cross-origin相似,只是不允許referrer資訊顯示在從https網站到http網站的請求中(安全降級)。
unsaft-url 瀏覽器總是會將完整的URL資訊顯示在referrer欄位中,無論請求發給任何網站。

Referrer-Policy值不是固定不變的,而是可是通過程式手動設定,一般都會不會去手動更改除非網頁中不存在一些敏感資訊,那就預設使用no-referrer-when-downgrade。這裡就多說了,如果有興趣的可以調研一下。

Response Headers

這部分儲存的是響應頭資訊,當服務端接受到請求,並處理完成之後需要向客戶端做出應答。

cache-control: no-store, no-cache, must-revalidate
content-encoding: gzip
content-type: text/html; charset=UTF-8
date: Fri, 28 Jun 2019 09:32:09 GMT
expires: Thu, 19 Nov 1981 08:52:00 GMT
pragma: no-cache
status: 200
strict-transport-security: max-age=15768000; preload
x-hit: web1
  • cache-control:響應輸出到客戶端後,服務端通過該報文頭告訴客戶端如何控制響應內容的快取
  • content-encoding:文件編碼(Encode)方法。只有在解碼之後才可以得到Content-Type頭指定的內容型別
  • content-type:文件型別
  • date:當前的GMT時間,可以用setDateHeader來設定
  • expires:文件過期時間,文件到期後則不再快取
  • pragma:設定訊息頭,(no-cache)強制清除快取
  • status:伺服器響應狀態碼
  • strict-transport-security:安全功能,它告訴瀏覽器只能通過HTTPS訪問當前資源,而不是HTTP
Request Headers

這部分承載的是請求頭的資訊,當客戶端向服務端傳送請求時,需要傳遞給服務端的資訊內容。

:authority: segmentfault.com
:method: GET
:path: /search?q=1
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cookie: e23800c454aa573c0ccb16b52665ac26=1561712973
referer: https://segmentfault.com/
user-agent: Chrome/75.0.3770.100 Safari/537.
  • :authority:請求許可權(HTTP2.0)
  • :method:請求方式(HTTP2.0)
  • :path:請求地址(HTTP2.0)
  • :scheme:請求協議(HTTP2.0)
  • accept:指定客戶端可以接受的內容型別,比如文字,圖片,應用等等,內容的先後排序表示客戶端接收的先後次序,每種型別之間用逗號隔開。
  • accept-encoding:客戶端接收編碼型別,一些網路壓縮格式:Accept-Encoding: gzip, deflate, sdch。相對來說,deflate是一種過時的壓縮格式,現在常用的是gzip
  • accept-language:客戶端可以接受的語⾔言型別,引數值規範和 accept的很像。一般就接收中文和英文,有其他語言需求自行新增。
  • cookie:同樣是一個比較關鍵的欄位,Cookie是 client 請求伺服器時,伺服器會返回一個鍵值對樣的資料給瀏覽器,下一次瀏覽器再訪問這個域名下的網頁時,就需要攜帶這些鍵值對資料在 Cookie中,用來跟蹤瀏覽器使用者的訪問前後路徑。
  • referer:瀏覽器上次訪問的網頁url,uri。由於http協議的無記憶性,伺服器可從這裡瞭解到客戶端訪問的前後路徑,並做一些判斷,如果⼀次訪問的 url 不能從前一次訪問的頁面上跳轉獲得, 在一定程度上說明了請求頭有可能偽造。
  • user-agent:中文名使用者代理,伺服器從此處知道客戶端的作業系統型別和版本,電腦CPU型別,瀏覽器 種類版本,瀏覽器渲染引擎,等等。

accept-language共分為下列幾種:

zh-CN:中文簡體大陸
zh:其他中文
en-US:英語美語
en:其他英語

Cookie就是儲存在客戶端的一小段文字,因為cookie是儲存在客戶端瀏覽器中的,Cookie不能作為程式碼執行,也不會傳送病毒,且為你所專有,並只能由提供它的伺服器來讀取。儲存的資訊片斷以名/值對(name-value)的形式儲存,一個名/值對僅僅是一條命名的資料。一個網站只能取得它放在你的電腦中的資訊,它無法從其它的cookie檔案中取得資訊,也無法得到你的電腦上的其它任何東西。

const express = require('express');
const cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser('sign'));
app.get('/set', function(req, res) {
    res.cookie('name', 'TracyYu', {maxAge: 9999999, httpOnly: true, signed: true});
    res.send('cookie設定成功');
})
app.get('/get', function(req, res) {
    console.log(req.signedCookies);
    res.send('success')
})
app.listen('3000', function() {
    console.log('3000成功');
})

通過上面程式碼中對cookie進行設定之後,使用者訪問/set路由的是時候已經把cookie設定到了瀏覽器的頭部,當使用者訪問/get路由的時候,由於在瀏覽器中已經設定好cookie,在同屬於一個服務的情況下是可以直接獲取到cookie的。當然除了上述所說,通過document也是可以手動設定cookie的,在客戶端設定的cookie在服務端同樣是也可以獲取到的。

document.cookie="userId=929";

這樣就將名為userIdcookie值設定為了929,現在訪問/get同樣就能拿到在客戶端設定的cookie值了。

請求方式

http中經常用的到的就是getpost兩種,在開發過程中會遵循RESTful介面風格,這是一種現在比較流行的介面風格,使用這種介面風格需要用到一些其他的請求方式,http請求方式一共有8種。

請求方式 描述
OPTIONS 允許客戶端檢視伺服器的效能,伺服器針對特定資源所支援的HTTP請求方法,也可以利用向web伺服器傳送‘*’的請求來測試伺服器的功能性
HEAD 向伺服器索與GET請求相一致的響應,只不過響應體將不會被返回。這一方法可以再不必傳輸整個響應內容的情況下,就可以獲取包含在響應小訊息頭中的元資訊。
GET 向特定的資源發出請求。它本質就是傳送一個請求來取得伺服器上的某一資源。資源通過一組HTTP頭和呈現資料(如HTML文字,或者圖片或者視訊等)返回給客戶端。GET請求中,永遠不會包含呈現資料。
POST 向指定資源提交資料進行處理請求(例如提交表單或者上傳檔案)。資料被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。
PUT 向指定資源位置上傳其最新內容
DELETE 請求伺服器刪除Request-URL所標識的資源
TRACE 回顯伺服器收到的請求,主要用於測試或診斷
CONNECT HTTP/1.1協議中預留給能夠將連線改為管道方式的代理伺服器。

HTTP定義了與伺服器互動的不同方法,最基本的方法是GETPOST(開發關心的只有GET請求和POST請求)。

GET和POST長度的限制問題
GET POST
GET是通過URL提交資料,因此GET可提交的資料量就跟URL所能達到的最大長度有直接關係 HTTP協議沒有對POST進行任何限制,一般是受伺服器配置限制或者記憶體大小
HTTP協議對URL長度是沒有限制的;限制URL長度大多數是瀏覽器或者伺服器的配置引數 PHP下可以修改php.conf的postmaxsize來設定POST的大小

其實這裡有一個很大的誤區,http協議並未規定GETPOST的長度限制,GET的最大長度限制是因為瀏覽器和web伺服器限制了URL的長度,不同的瀏覽器和web伺服器,限制的最大長度不一樣,要支援IE,則最大長度為2083byte,若支援Chrome,則最大長度8182byte,首先即使GET有長度限制,也是限制的整個URL的長度,而不僅僅是引數值資料長度。

GET和POST的安全性
  1. GET是通過URL方式請求,可以直接看到,明文傳輸
  2. POST是通過請求header請求,可以開發者工具或者抓包可以看到,同樣也是明文的
  3. GET請求會儲存在瀏覽器歷史紀錄中,還可能會儲存在Web的日誌中

GET請求指定資源的表示形式。注意,GET不應該用於產生副作用的操作,比如在web應用程式中使用它執行操作。原因之一是GET可能被機器人或爬行器任意使用,它們不需要考慮請求應該引起的副作用。POST將要處理的資料(例如,從HTML表單)提交給標識的資源。資料包含在請求體中。這可能會導致建立新資源或更新現有資源,或者兩者兼而有之。使用HTTP協議的服務不應該使用基於GET的表單來提交敏感資料,因為這會導致這些資料在Request-URI中編碼。許多現有伺服器,代理和使用者代理會將請求URI記錄在第三方可能看到的某個位置。伺服器可以使用基於POST的表單提交。

GET與POST請求過程

POST請求的過程:

  1. 瀏覽器請求tcp連線(第一次握手)
  2. 伺服器答應進行tcp連線(第二次握手)
  3. 瀏覽器確認,併傳送post請求頭(第三次握手,這個報文比較小,所以http會在此時進行第一次資料傳送)
  4. 伺服器返回100 Continue響應
  5. 瀏覽器傳送資料
  6. 伺服器返回200 OK響應

GET請求的過程:

  1. 瀏覽器請求tcp連線(第一次握手)
  2. 伺服器答應進行tcp連線(第二次握手)
  3. 瀏覽器確認,併傳送get請求頭和資料(第三次握手,這個報文比較小,所以http會在此時進行第一次資料傳送)
  4. 伺服器返回200OK響應

總結

原本想說一些狀態碼相關的東西,但是簡單的看了一下,好像又沒有什麼好說的,百度百科說的也很清楚,就不在文章裡面贅述了。

簡單的對http協議做了一些小的介紹與總結,如果文章中有哪些地方有問題,請在下方留言指正,我會盡快做出改正。

相關文章