本文已同步到github, web開發中,必需要了解的HTTP相關知識,歡迎收藏,歡迎star。javascript
本文主要記錄與HTTP相關的具體概念和知識,關於HTTP協議的誕生和歷史發展,很少作介紹,可是既然是寫HTTP,順帶說兩句,上下文也能銜接的上。html
CERN(歐洲核子研究組織)的蒂姆 • 伯納斯 - 李(Tim Berners - Lee)博士提出了一種能讓遠隔兩地的研究者們共享知識的設想,因而HTTP慢慢的誕生了。java
另外,HTTP協議是無狀態協議,因而爲了保存用戶的狀態,cookie誕生了。node
HTTP協議是創建在TCP鏈接之上的,當瀏覽器輸入URL進行訪問,瀏覽器衝URL中解析出主機名和端口,瀏覽器創建一條與web服務器的鏈接,而後才進行http請求。git
在客戶端與服務端進行http通訊以前,須要創建TCP鏈接,這時須要三次握手github
(1) 請求新的TCP鏈接,客戶端發送一個小的TCP分組,這個分組設置一個特殊的SYN標記,代表是一個客戶端請求。web
(2) 若是服務器接受這個鏈接,就會對一些鏈接參數進行計算,並向客戶端回送一個TCP分組,發送SY和ACK標記,代表鏈接請求已經被接受跨域
(3) 最後,客戶端向服務器回送一條確認消息,通知服務器鏈接已經創建。瀏覽器
創建一個鏈接須要三次握手,而終止一個鏈接要通過4次握手。這由TCP的半關閉(half-close)形成的。既然一個TCP鏈接是全雙工(即數據在兩個方向上能同時傳遞),所以每一個方
向必須單獨地進行關閉。這原則就是當一方完成它的數據發送任務後就能發送一個FIN來終止
這個方向鏈接。當一端收到一個FIN,它必須通知應用層另外一端幾經終止了那個方向的數據傳
送。發送FIN一般是應用層進行關閉的結果。
(1) 客戶端發送FIN標記到服務器,代表客戶端發起關閉鏈接緩存
(2) 服務器接收客戶端的FIN標記並,向客戶端發送FIN的ACK確認標記
(3) 服務器發送FIN到客戶端,服務器關閉鏈接
(4) 服務器端發送一個FIN的ACK確認標記,確認鏈接關閉
創建持久鏈接的請求和響應交互:
使用wireshark進行數據抓包:
這裏向你們推薦一款抓包軟件Wireshark,能夠用來分析TCP鏈接的創建和斷開過程,以及抓取HTTP請求和相應的信息等,下面是我進行一次客戶端和服務端通訊的抓包數據截圖:
HTTP協議報文是應用程序之間發送的數據塊,也就是客戶端和服務端用於交互的信息。客戶端的報文叫作請求報文,服務器端的報文叫作響應報文。
HTTP報文由起始行、首部和實體的主體(也稱報文主體或主體)組成。起始行和首部以一個回車符和換行符做爲結束,主體部分能夠是二進制數據,也能夠爲空。
請求報文起始行:
請求報文起始行說明了要作什麼,由請求方法 、請求URI和協議版本構成。
GET /index.html HTTP/1.1
響應報文起始行:
響應報文的起始行,由協議版本、狀態碼和緣由短語構成。
HTTP/1.1 200 OK // OK就是緣由短語
首部字段分類
1.通用首部
客戶端和服務端均可以使用的首部
通用首部字段表:
2.請求首部
請求報文特有的首部,爲服務器提供了一些額外的信息,補充了請求的附加內容、客戶端信息、響應內容相關的優先級等信息。
請求首部字段
3.響應首部
響應報文特有的字段
響應首部字段表:
4.實體首部
用於針對請求報文和響應報文主體部分使用的首部
5.擴展首部
擴展首部是非標準的首部,由應用程序開發者建立,但還未添加到已批准的HTTP標準中去。
狀態碼的職責是當客戶端向服務器端發送請求時,描述返回的請求結果。藉助狀態碼,用戶能夠知道服務器端是正常處理了請求,仍是出現了錯誤。
狀態碼分類:
狀態碼區間 | 類別 |
---|---|
100~199 | 信息性狀態碼 |
200~299 | 成功狀態碼 |
300~399 | 重定向狀態碼 |
400~499 | 客戶端錯誤狀態碼 |
500~599 | 服務器錯誤狀態碼 |
經常使用狀態碼列表:
狀態碼 | 緣由短語 | 含義 |
---|---|---|
200 | OK | 表示從客戶端發來的請求在服務器端被正常處理了 |
204 | No Content | 該狀態碼錶明服務器接收的請求已成功處理,但在返回的響應報文中不含實體的主體部分。另外,也不容許返回任何實體的主體。 |
301 | Moved Permanently | 永久重定向,該狀態碼錶示請求的資源已被分配了新的 URI,之後應使用資源如今所指的 URI |
302 | Found | 臨時性重定向,該狀態碼錶示請求的資源已被分配了新的 URI,但願用戶(本次)能使用新的 URI 訪問 |
303 | See Other | 303 狀態碼和 302 Found 狀態碼有着相同的功能,但 303 狀態碼明確表示客戶端應當採用 GET 方法獲取資源,這點與 302 狀態碼有區別 |
304 | Not Modified | 緩存 |
307 | Temporary Redirect | 臨時重定向,和302同樣 |
400 | Bad Request | 該狀態碼錶示請求報文中存在語法錯誤。當錯誤發生時,需修改請求的內容後再次發送請求。另外,瀏覽器會像 200 OK 同樣對待該狀態碼 |
401 | Unauthorized | 該狀態碼錶示發送的請求須要有經過 HTTP 認證(BASIC 認證、DIGEST 認證)的認證信息 |
403 | Forbidden | 該狀態碼代表對請求資源的訪問被服務器拒絕了 |
404 | Not Found | 該狀態碼代表服務器上沒法找到請求的資源 |
500 | Internal Server Error | 該狀態碼代表服務器端在執行請求時發生了錯誤。也有多是 Web應用存在的 bug 或某些臨時的故障 |
502 | Bad Gateway | 網關錯誤 |
503 | Service Unavailable | 該狀態碼代表服務器暫時處於超負載或正在進行停機維護,如今沒法處理請求。若是事先得知解除以上情況須要的時間,最好寫入RetryAfter 首部字段再返回給客戶端 |
跨域資源共享( CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不一樣源服務器上的指定的資源。當一個資源從與該資源自己所在的服務器不一樣的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。 --MDN
下面使用nodejs來搭建一個簡單的服務器,來介紹一個跨域問題的解決方法
// index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>CORS</title> </head> <body> Hello World <script> fetch('http://127.0.0.1:8081') </script> </body> </html>
// server.js const http = require('http') http.createServer(function(req, res) { res.writeHead('200', { 'Access-Control-Allow-Origin': 'http://localhost:8082' }) }).listen(8081)
在源地址爲 http://localhost:8082 下,請求http://localhost:8081,是跨域請求,瀏覽器會自動在request Header中發送Origin首部字段,並把值設置爲來自哪一個源,本例爲http://localhost:8082。服務器須要在響應頭中設置Access-Control-Allow-Origin,來告知瀏覽器能夠處理返回的數據。若是響應頭中不設置Access-Control-Allow-Origin則會報錯,可是返回狀態碼爲200,跨域其實是瀏覽器自己的一個安全機制。
// server2.js // 啓動8082端口服務,在瀏覽器中訪問http://127.0.0.1:8082,會返回index.html內容 const http = require('http') const fs = require('fs') http.createServer(function(req, res) { var page = fs.readFileSync('index.html', 'utf-8') res.writeHead(200, { 'Content-Type': 'text/html' }) res.end(page) }).listen(8082)
關於CORS跨域請求的分類:
1.簡單請求:
須要同時知足如下的條件就是簡單請求
(1)請求方法:
GET、POST、HEAD
(2)請求頭不能爲如下其餘字段以外
Accept Accept-Language Content-Language Content-Type的值必須爲application/x-www-form-urlencoded、multipart/form-data、text/plain之一
2.非簡單請求:
非簡單請求是當請求信息不知足簡單請求的條件,瀏覽器就發送方法爲OPTIONS的預請求,包含本身請求的方法及須要使用的請求頭字段,在獲得服務器響應容許以後,瀏覽器會按照想要使用的請求方法及頭信息再發一次請求。
如今修改如下上面的例子:
// index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>CORS</title> </head> <body> Hello World <script> fetch('http://127.0.0.1:8081', { method: 'PUT', headers: { X-Coustom-Head: 'abc' } }) </script> </body> </html>
// server.js const http = require('http') http.createServer(function(req, res) { res.writeHead('200', { 'Access-Control-Allow-Origin': 'http://localhost:8082' }) }).listen(8081)
若是服務端不進行相應的設置告訴瀏覽器容許跨域訪問則會報錯
可是預請求返回狀態碼爲200
// server2.js // 啓動8082端口服務,在瀏覽器中訪問http://127.0.0.1:8082,會返回index.html內容 const http = require('http') const fs = require('fs') http.createServer(function(req, res) { var page = fs.readFileSync('index.html', 'utf-8') res.writeHead(200, { 'Content-Type': 'text/html' }) res.end(page) }).listen(8082)
如今咱們修改如下 server.js
// server.js const http = require('http') http.createServer(function(req, res) { res.writeHead('200', { 'Access-Control-Allow-Origin': 'http://localhost:8082', 'Access-Control-Allow-Headers': 'X-Coustom-Head', 'Access-Control-Allow-Methods': 'PUT' }) }).listen(8081)
從新啓動node服務,訪問http://locaohost:8082,能夠看到在發送預請求後,瀏覽器會繼續發送PUT請求
關於CORS的其餘設置這裏就很少作介紹了,這裏主要是用一個例子來講明如下http不一樣字段在跨域場景下的做用。
本例依舊用node服務來說解一下Cache-Control的做用,新建三個文件
// index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Cache-Control</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <script src="/script.js"></script> </body> </html>
// script.js console.log('script.js')
// server.js const http = require('http') const fs = require('fs') http.createServer(function(req, res) { if (req.url === '/') { let page = fs.readFileSync('index2.html', 'utf-8') res.writeHead(200, { 'Content-Type': 'text/html' }) res.end(page) } if (req.url === '/script.js') { let page = fs.readFileSync('script.js', 'utf-8') res.writeHead(200, { 'Content-Type': 'text/javascript', 'Cache-Control': 'max-age=10' }) res.end(page) } }).listen(8082)
在第一次請求script.js資源時,向服務器發送請求
因爲服務器返回響應時,設置Cache-Control: 'max-age=10'時,修改script.js後,在10秒內繼續請求script.js資源,則從緩存中讀取,而打印信息依舊是'script.js'
// script.js console.log('script-modify.js')
更多關於緩存的知識在這裏也很少介紹了,貼兩張cache-control字段在請求和響應時能夠設置的值和其表示含義:
1. Cache-Control 緩存請求指令:
2. Cache-Control 緩存響應指令:
指某些網站爲了辨別用戶身份、進行 session 跟蹤而儲存在用戶本地終端上的數據(一般通過加密),當下次再訪問時瀏覽器會將該網站的cookie發回給服務器端。
cookie若是不設置過時時間,隨瀏覽器關閉而失效,若是有須要能夠設置過時時間,繼續上代碼例子🌰,新建兩個文件以下
// index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Cookie</title> </head> <body> Cookie <script> console.log(document.cookie) </script> </body> </html>
// server.js const http = require('http') const fs = require('fs') http.createServer(function(req, res) { if (req.url === '/') { let page = fs.readFileSync('index.html', 'utf-8') res.writeHead(200, { 'Content-Type': 'text/html', 'Set-Cookie': ['a=1;max-age:5', 'b=2;HTTPOnly'] }) res.end(page) } }).listen(8082)
啓動node服務,訪問localhost:8082,能夠看到成功設置了cookie
並在響應頭信息中設置了Set-Cookie字段
另外關注如下打印信息,發現只有a=1,由於給b=2設置了HttpOnly屬性,不容許JavaScript經過腳原本獲取到cookie信息
因爲當再次請求時,cookie會在請求頭中發送到服務器,因爲cookie a=1設置了5秒後過時,在5秒後刷新頁面,請求頭中的cookie只有a=1
在5秒內發送二次請求,cookie a=1沒有失效,在請求頭中cookie a=1;b=2都會發送到服務器
另外對於cookie的其餘設置如expires、domain等在這裏也很少作介紹了
當服務端返回30一、30二、307等狀態碼都表明資源已經被重定向到其餘位置,301表示永久改變URI,302和307表示臨時重定向到某個URI
本例舉一個服務器返回302狀態碼的例子,直接上代碼:
// server.js const http = require('http'); const fs = require('fs') http.createServer((req, res) => { if (req.url === '/') { res.writeHead(302, { 'Location': '/redirect' }) res.end() } if (req.url === '/redirect') { res.end('redirect') } }).listen(8082);
訪問localhost:8082, 服務器返回302狀態碼時,在相應頭中設置Location首部字段,瀏覽器會繼續發送請求到重定向的地址
首先說一下什麼是HTTPS
HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer 或 Hypertext Transfer Protocol Secure,超文本傳輸安全協議),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL。 --百度百科
HTTPS = HTTP+ 加密 + 認證 + 完整性保護
最主要是在應用層和傳輸層中間加了一個SSL(安全套階層),一般,HTTP 直接和 TCP 通訊。當使用 SSL 時,則演變成先和 SSL 通訊,再由 SSL 和 TCP 通訊。
HTTP與HTTPS的區別:
本文主要介紹HTTP,關於HTTPS主要就介紹這麼多吧。
本想說點HTTP2的知識,奈何本身是小白,放個百度百科的連接吧 HTTP2。
等後續隨着不斷的學習,再回來更新本文。
另外放一個HTTP1.1與HTTP2請求與相應對比的demo的連接HTTP/2 is the future of the Web, and it is here!
最後,本文主要介紹了一些HTTP在web開發中的基礎知識,關於概念和圖解流程的截圖基本上都是來自《TCP/IP詳解 卷1:協議》、《圖解HTTP》、《HTTP權威指南》,可放心參考。筆者功力實在有限,若有問題,請你們多多指出,相互學習和進步,也但願經過個人學習與實踐過程,整理出的筆記能對你們有所幫助,謝謝。
本文參考連接: