html
🎁 本文已收錄於 CS-Wiki(Gitee 官方推薦項目,現已 0.9k star)git
面試
Web 界面固然不會憑空出來,根據 Web 瀏覽器地址欄中指定的 URL,Web 使用一種名爲 HTTP 的協議做爲規範,完成從客戶端到服務端的一些流程。能夠說,Web 是創建在 HTTP 協議上進行通訊的。算法
其實,在 1983 年 3 月以前,互聯網還只屬於少數人,全世界的網民之間的信息是沒法共享的。在這一互聯網的黎明時期,HTTP 應運而生。數據庫
歐洲核子研究組織的 Tim Berners-Lee 博士提出了一種可以讓遠隔兩地的網民共享知識的設想,最初的理念是:藉助多文檔之間相互關聯的超文本(HyperTest),連成可相互參閱的 WWW(World Wide Web,萬維網)。後端
如今已提出了 3 項 WWW 構建技術,分別是:瀏覽器
把 SGML(標準通用標記語言)做爲頁面的文本標記語言 HTML安全
做爲文檔傳遞協議的 HTTP服務器
指定文檔所在地址的 URL網絡
WWW 這一名稱,是 Web 瀏覽器當年用來瀏覽超文本的客戶端應用程序的名稱,如今用來表示這一系列的集合,也可簡稱爲 Web。
說了這麼多,你們只知道 HTTP 很牛逼,對 HTTP 是什麼仍然沒有很直觀的概念。別急,在瞭解什麼是 HTTP 以前,咱們有必要知道超文本是什麼。
HTTP 傳輸的內容就是超文本:
咱們先來理解「文本」:在互聯網早期的時候只是簡單的字符文字,但隨着技術的發展,如今「文本」的涵義已經能夠擴展爲圖片、視頻、壓縮包等,在 HTTP 眼裏這些都算作「文本」。
再來理解「超文本」:它就是超越了普通文本的文本,它是文字、圖片、視頻等的混合體。最關鍵有超連接,能從一個超文本跳轉到另一個超文本。
HTML 就是最多見的超文本了,它自己只是純文字文件,但內部用不少標籤訂義了圖片、視頻等的連接,在通過瀏覽器的解析,呈現給咱們的就是一個文字、有畫面的網頁了。
OK,下面咱們正式介紹什麼是 HTTP?
HTTP:超文本傳輸協議(HyperText Transfer Protocol)是當今互聯網上應用最爲普遍的一種網絡協議。全部的 WWW(萬維網) 文件都必須遵照這個標準。HTTP 和 TCP/IP 協議簇中的衆多協議同樣,用於客戶端和服務器端之間的通訊。
至今被世人普遍使用的 HTTP 協議,仍然是 20 多年前的版本。也就是說,做爲 Web 文檔傳輸協議的 HTTP,它的版本幾乎沒有更新,從另外一方面來講,前人的智慧真的牛逼 👍
HTTP/0.9:HTTP 於 1990 年問世,功能簡陋,僅支持 GET 請求方式,而且僅能訪問 HTML 格式的資源。那時的 HTTP 並無做爲正式的標準被創建,所以被被稱爲 HTTP 0.9。
HTTP/1.0:1996 年 5 月 HTTP 正式做爲標準被公佈,版本號爲 HTTP 1.0。在 0.9 版本上作了進步,增長了請求方式 POST 和 HEAD;再也不侷限於 0.9 版本的 HTML 格式,根據 Content-Type 能夠支持多種數據格式...... 須要注意的是:1.0 版本的工做方式是短鏈接。雖然說 HTTP/1.0 是初期標準,但該協議標準至今仍然在被普遍使用。
HTTP/1.1:1997 年公佈的 HTTP 1.1 是目前主流的 HTTP 協議版本。當年的 HTTP 協議的出現主要是爲了解決文本傳輸的難題,如今的 HTTP 早已超出了 Web 這個框架的侷限,被運用到了各類場景裏。固然,1.1 版本的最大變化,就是引入了長鏈接以及流水線機制(管道機制)。
這裏面出現的各類專有名詞你們留個印象就行,下文會逐漸講解。
與 URI(統一資源標識符) 相比,你們應該更熟悉 URL(Uniform Resource Location,統一資源定位符),URL 就是咱們使用 Web 瀏覽器訪問 Web 頁面時須要輸入的網頁地址。好比 http://baidu.com
。
URI 是 Uniform Resource Identifier 的縮寫,RFC 2386 分別對這三個單詞進行以下定義:
Uniform:統一規定的格式可方便處理多種不一樣類型的資源
Resource:資源的定義是可標識的任何東西。不只能夠是單一的,也能夠是一個集合
Identifier:標識可標識的對象。也稱爲標識符
綜上,URI 就是由某個協議方法表示的資源的定位標識符。好比說,採用 HTTP 協議時,協議方案就是 http
,除此以外,還有 ftp
、telnet
等,標準的 URI 協議方法有 30 種左右。
URI 有兩種格式,相對 URI 和絕對 URI。
相對 URI:指從瀏覽器中基本 URI 處指定的 URL,形如 /user/logo.png
絕對 URI:使用涵蓋所有必要信息
總結來講:URI 用字符串標識某一處互聯網資源,而 URL 標識資源的地點(互聯網上所處的位置),可見 URL 是 URI 的子集。
HTTP 協議規定,在兩臺計算機之間使用 HTTP 協議進行通訊時,在一條通訊線路上一定有一端是客戶端,另外一端則是服務端。當在瀏覽器中輸入網址訪問某個網站時, 你的瀏覽器(客戶端)會將你的請求封裝成一個 HTTP 請求發送給服務器站點,服務器接收到請求後會組織響應數據封裝成一個 HTTP 響應返回給瀏覽器。換句話說,確定是先從客戶端開始創建通訊的,服務器端在沒有接收到請求以前不會發送響應。
下面咱們詳細分析一下 HTTP 的請求報文和響應報文
HTTP 請求報文由 3 大部分組成:
1)請求行(必須在 HTTP 請求報文的第一行)
2)請求頭(從第二行開始,到第一個空行結束。請求頭和請求體之間存在一個空行)
3)請求體(一般以鍵值對 {key:value}
方式傳遞數據)
舉個請求報文的例子:
請求行開頭的 POST
表示請求訪問服務器的類型,稱爲方法(method)。隨後的字符串 /form/login
指明瞭請求訪問的資源對象,也叫作請求 URI(request-URI)。最後的 HTTP/1.1
即 HTTP 的版本號,用來提示客戶端使用的 HTTP 協議功能。
綜上來看,這段請求的意思就是:請求訪問某臺 HTTP 服務器上的 /form/login
頁面資源,並附帶參數 name = veal、age = 37。
注意,不管是 HTTP 請求報文仍是 HTTP 響應報文,請求頭/響應頭和請求體/響應體之間都會有一個空行,且請求體/響應體並非必須的。
請求行中的方法的做用在於能夠指定請求的資源按照指望產生某種行爲,即使用方法給服務器下命令。
包括(HTTP 1.1):GET
、POST
、PUT
、HEAD
、DELETE
、OPTIONS
、CONNECT
、TRACE
。固然,咱們在開發中最多見也最常使用的就只有前面三個。
1)GET 獲取資源
GET 方法用來請求訪問已被 URI 識別的資源。指定的資源經服務器端解析後返回響應內容
使用 GET 方法請求-響應的例子:
2)POST 傳輸實體主體
POST 主要用來傳輸數據,而 GET 主要用來獲取資源。
使用 POST 方法請求-響應的例子:
3)PUT 傳輸文件
PUT 方法用來傳輸文件,因爲自身不帶驗證機制,任何人均可以上傳文件,所以存在安全性問題,通常不使用該方法。
使用 PUT 方法請求-響應的例子:
4)HEAD 獲取報文首部
和 GET 方法相似,可是不返回報文實體主體部分。主要用於確認 URI 的有效性以及資源更新的日期時間等。
使用 HEAD 方法請求-響應的例子:
5)DELETE 刪除文件
與 PUT 功能相反,用來刪除文件,而且一樣不帶驗證機制,按照請求 URI 刪除指定的資源。
使用 DEELTE 方法請求-響應的例子:
6)OPTIONS 查詢支持的方法
用於獲取當前 URI 所支持的方法。若請求成功,會在 HTTP 響應頭中包含一個名爲 「Allow
」 的字段,值是所支持的方法,如 「GET, POST」。
使用 OPTIONS 方法請求-響應的例子:
7)..........
請求頭用於補充請求的附加信息、客戶端信息、對響應內容相關的優先級等內容。如下列出常見請求頭:
1)Referer:表示這個請求是從哪一個 URI 跳過來的。好比說經過百度來搜索淘寶網,那麼在進入淘寶網的請求報文中,Referer 的值就是:http://www.javashuo.com/tag/www.baidu.com。若是是直接訪問就不會有這個頭。這個字段一般用於防盜鏈。
2)Accept:告訴服務端,該請求所能支持的響應數據類型。(對應的,HTTP 響應報文中也有這樣一個相似的字段 Content-Type
,用於表示服務端發送的數據類型,若是 Accept
指定的類型和服務端返回的類型不一致,就會報錯)
上圖中的 text/plain;q = 0.3
表示對於 text/plain
媒體類型的數據優先級/權重爲 0.3(q 的範圍 0 ~ 1)。不指定權重的,默認爲 1.0。
數據格式類型以下圖:
3)Host:告知服務器請求的資源所處的互聯網主機名和端口號。該字段是 HTTP/1.1 規範中惟一一個必須被 包含在請求頭中的字段。
4)Cookie:客戶端的 Cookie 就是經過這個報文頭屬性傳給服務端的!
Cookie: JSESSIONID=15982C27F7507C7FDAF0F97161F634B5
5)Connection:表示客戶端與服務鏈接類型;Keep-Alive 表示持久鏈接,close 已關閉
6)Content-Length:請求體的長度
7)Accept-Language:瀏覽器通知服務器,瀏覽器支持的語言
8)Range:對於只需獲取部分資源的範圍請求,包含首部字段 Range 便可告知服務器資源的指定範圍
9)......
HTTP的響應報文也由三部分組成:
響應行(必須在 HTTP 響應報文的第一行)
響應頭(從第二行開始,到第一個空行結束。響應頭和響應體之間存在一個空行)
響應體
在響應行開頭的 HTTP 1.1 表示服務器對應的 HTTP 版本。緊隨的 200 OK 表示請求的處理結果的狀態碼和緣由短語。
HTTP 狀態碼負責表示客戶端 HTTP 請求的的返回結果、標記服務器端處理是否正常、通知出現的錯誤等工做。(重中之重!!!,和咱們平常開發息息相關)
狀態碼由 3 位數字組成,第一個數字定義了響應的類別:
類別 | 緣由短語 | |
---|---|---|
1xx | Informational 信息性狀態碼 | 接收的請求正在處理 |
2xx | Success 成功狀態碼 | 請求正常處理完畢 |
3xx | Redirection 重定向狀態碼 | 須要進行附加操做以完成請求 |
4xx | Client Error 客戶端錯誤狀態碼 | 服務器沒法處理請求 |
5xx | Server Error 服務器錯誤狀態碼 | 服務器處理請求出錯 |
🔶 2xx:請求正常處理完畢
200 OK
:客戶端請求成功
204 No Content
:無內容。服務器成功處理,但未返回內容。通常用在只是客戶端向服務器發送信息,而服務器不用向客戶端返回什麼信息的狀況。不會刷新頁面。
206 Partial Content
:服務器已經完成了部分 GET 請求(客戶端進行了範圍請求)。響應報文中包含 Content-Range 指定範圍的實體內容
🔶 3xx:須要進行附加操做以完成請求(重定向)
301 Moved Permanently
:永久重定向,表示請求的資源已經永久的搬到了其餘位置。
302 Found
:臨時重定向,表示請求的資源臨時搬到了其餘位置
303 See Other
:臨時重定向,應使用GET定向獲取請求資源。303功能與302同樣,區別只是303明確客戶端應該使用GET訪問
304 Not Modified
:表示客戶端發送附帶條件的請求(GET方法請求報文中的IF…)時,條件不知足。返回304時,不包含任何響應主體。雖然304被劃分在3XX,但和重定向一毛錢關係都沒有
307 Temporary Redirect
:臨時重定向,和302有着相同含義。POST不會變成GET
🔶 4xx:客戶端錯誤
400 Bad Request
:客戶端請求有語法錯誤,服務器沒法理解。
401 Unauthorized
:請求未經受權,這個狀態代碼必須和 WWW-Authenticate 報頭域一塊兒使用。
403 Forbidden
:服務器收到請求,可是拒絕提供服務
404 Not Found
:請求資源不存在。好比,輸入了錯誤的 URL
415 Unsupported media type
:不支持的媒體類型
🔶 5xx:服務器端錯誤,服務器未能實現合法的請求。
500 Internal Server Error
:服務器發生不可預期的錯誤。
503 Server Unavailable
:服務器當前處於超負載或正在停機維護,暫時不能處理客戶端的請求,一段時間後可能恢復正常
響應頭也是用鍵值對 k:v,用於補充響應的附加信息、服務器信息,以及對客戶端的附加要求等。
這裏着重說明一下 Location
這個字段,能夠將響應接收方引導至與某個 URI 位置不一樣的資源。一般來講,該字段會配合 3xx:Redirection
的響應,提供重定向的 URI。
在 HTTP 協議的初始版本(HTTP/1.0)中,客戶端和服務器每進行一次 HTTP 會話,就創建一次鏈接,任務結束就中斷鏈接。當客戶端瀏覽器訪問的某個 HTML 或其餘類型的 Web 頁中包含有其餘的 Web 資源(如JavaScript 文件、圖像文件、CSS文件等),每遇到這樣一個 Web 資源,瀏覽器就會從新創建一個 HTTP 會話。這種方式稱爲短鏈接(也稱非持久鏈接)。
也就是說每次 HTTP 請求都要從新創建一次鏈接。因爲 HTTP 是基於 TCP/IP 協議的,因此鏈接的每一次創建或者斷開都須要 TCP 三次握手或者 TCP 四次揮手的開銷。
顯然,這種方式存在巨大的弊端。好比訪問一個包含多張圖片的 HTML 頁面,每請求一張圖片資源就會形成無謂的 TCP 鏈接的創建和斷開,大大增長了通訊量的開銷
從 HTTP/1.1 起,默認使用長鏈接也稱持久鏈接 keep-alive。使用長鏈接的 HTTP 協議,會在響應頭加入這行代碼:Connection:keep-alive
在使用長鏈接的狀況下,當一個網頁打開完成後,客戶端和服務器之間用於傳輸 HTTP 數據的 TCP 鏈接不會關閉,客戶端再次訪問這個服務器時,會繼續使用這一條已經創建的鏈接。Keep-Alive 不會永久保持鏈接,它有一個保持時間,能夠在不一樣的服務器軟件(如 Apache)中設定這個時間。實現長鏈接須要客戶端和服務端都支持長鏈接。
HTTP 協議的長鏈接和短鏈接,實質上是 TCP 協議的長鏈接和短鏈接。
默認狀況下,HTTP 請求是按順序發出的,下一個請求只有在當前請求收到響應以後纔會被髮出。因爲受到網絡延遲和帶寬的限制,在下一個請求被髮送到服務器以前,可能須要等待很長時間。
持久鏈接使得多數請求以流水線(管線化 pipeline)方式發送成爲可能,即在同一條持久鏈接上連續發出請求,而不用等待響應返回後再發送,這樣就能夠作到同時並行發送多個請求,而不須要一個接一個地等待響應了。
HTTP 協議是無狀態協議。也就是說他不對以前發生過的請求和響應的狀態進行管理,即沒法根據以前的狀態進行本次的請求處理。
這樣就會帶來一個明顯的問題,若是 HTTP 沒法記住用戶登陸的狀態,那豈不是每次頁面的跳轉都會致使用戶須要再次從新登陸?
固然,不能否認,無狀態的優勢也很顯著,因爲沒必要保存狀態,天然就減小了服務器的 CPU 及內存資源的消耗。另外一方面,正式因爲 HTTP 簡單,因此纔會被如此普遍應用。
這樣,在保留無狀態協議這個特徵的同時,又要解決無狀態致使的問題。方案有不少種,其中比較簡單的方式就是使用 Cookie 技術。
Cookie
經過在請求和響應報文中寫入 Cookie 信息來控制客戶端的狀態。具體來講,Cookie 會根據從服務器端發送的響應報文中的一個叫做 Set-Cookie
的首部字段信息,通知客戶端保存 Cookie。當下次客戶端再往服務器發送請求時,客戶端會自動在請求報文中加入 Cookie 值發送出去。服務器端收到客戶端發來的 Cookie 後,會去檢查到底是哪個客戶端發來的鏈接請求,而後對比服務器上的記錄,最後獲得以前的狀態信息。
形象來講,在客戶端第一次請求後,服務器會下發一個裝有客戶信息的身份證,後續客戶端請求服務器的時候,帶上身份證,服務器就能認得了。
下圖展現了發生 Cookie 交互的情景:
1)沒有 Cookie 信息狀態下的請求:
對應的 HTTP 請求報文(沒有 Cookie 信息的狀態)
GET /reader/ HTTP/1.1
Host: baidu.com
* 首部字段沒有 Cookie 的相關信息
對應的 HTTP 響應報文(服務端生成 Cookie 信息)
HTTP/1.1 200 OK
Date: Thu, 12 Jul 2020 15:12:20 GMT
Server: Apache
<Set-Cookie: sid=1342077140226; path=/; expires=Wed, 10-Oct-12 15:12:20 GMT>
Content-Type: text/plain; charset=UTF-8
2)第 2 次之後的請求(存有 Cookie 信息狀態)
對應的 HTTP 請求報文(自動發送保存着的 Cookie 信息)
GET /image/ HTTP/1.1
Host: baidu.com
Cookie: sid=1342077140226
所謂斷點續傳指的是下載傳輸文件能夠中斷,以後從新下載時能夠接着中斷的地方開始下載,而沒必要從頭開始下載。斷點續傳須要客戶端和服務端都支持。
這是一個很是常見的功能,原理很簡單,其實就是 HTTP 請求頭中的字段 Range
和響應頭中的字段 Content-Range
的簡單使用。客戶端一塊一塊的請求數據,最後將下載回來的數據塊拼接成完整的數據。打個比方,瀏覽器請求服務器上的一個服務,所發出的請求以下:
假設服務器域名爲 http://www.javashuo.com/tag/www.baidu.com,文件名爲 down.zip。
GET /down.zip HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, application/msword, application/vnd.ms-powerpoint, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep-Alive
服務器收到請求後,按要求尋找請求的文件,提取文件的信息,而後返回給瀏覽器,返回信息以下:
200
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon, 30 Apr 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT
OK,那麼既然要斷點續傳,客戶端瀏覽器請求服務器的時候要多加一條信息 — 從哪裏開始請求數據。 好比要求從 2000070 字節開始:
GET /down.zip HTTP/1.0
User-Agent: NetFox
RANGE: bytes=2000070-
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
仔細看一下就會發現多了一行 RANGE: bytes=2000070-
。這一行的意思就是告訴服務器 down.zip 這個文件從 2000070 字節開始傳,前面的字節不用傳了。
服務器收到這個請求之後,返回的信息以下:
206
Content-Length=106786028
Content-Range=bytes 2000070-106786027/106786028
Date=Mon, 30 Apr 2001 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT
和前面服務器返回的信息比較一下,就會發現增長了一行: Content-Range=bytes 2000070-106786027/106786028
。返回的代碼也改成 206 了,而再也不是 200 了。
到如今爲止,咱們已經瞭解到了 HTTP 具備至關優秀和方便的一面,而後,事務皆有兩面性,他也是有不足之處的:
通訊使用明文(不加密),內容可能被竊聽
不驗證通訊對方的身份,所以有可能遭遇假裝
沒法證實報文的完整性,因此有可能被篡改
這些問題不只在 HTTP 上出現,其餘未加密的協議中也存在相似問題,爲了解決 HTTP 的痛點,HTTPS 應用而生,說白了 HTTP + 加密 + 認證 + 完整性保護就是 HTTPS 協議
博主東南大學研究生在讀,利用課餘時間運營一個公衆號『 飛天小牛肉 』,2020/12/29 日開通,專一分享計算機基礎(數據結構 + 算法 + 計算機網絡 + 數據庫 + 操做系統 + Linux)、Java 基礎和麪試指南的相關原創技術好文。本公衆號的目的就是讓你們能夠快速掌握重點知識,有的放矢。但願你們多多支持哦,和小牛肉一塊兒成長 😃
並推薦我的維護的開源教程類項目: CS-Wiki(Gitee 推薦項目,現已 0.9k star), 致力打造完善的後端知識體系,在技術的路上少走彎路,歡迎各位小夥伴前來交流學習 ~ 😊