http詳解 一, http請求過程: 二, 網絡協議分層: 三, http歷史: 四, 跨域CORS 五, HTTP請求頭以及緩存Cache-Control 六 https:

1,http使用場景:

網頁輸入url
ajax獲取數據
img標籤加載圖片

2,主要技術點:緩存,這是最能優化性能的地方!!!

cache-control:
public,private
must-revalidate
no-chche,no-store

3,有意義的頭

Content-Type,Content-Encoding等用來約束數據類型
Cookie保持會話信息
CORS跨域且保證安全性限制,不讓非法人員使用

4,TCP連接問題:

三次握手
https鏈接創建過程,爲什麼安全
什麼是長鏈接,爲什麼需要長鏈接
http2信道複用爲什麼可以提高性能

一, http請求過程:


這些節點對web開發人員是透明的,但是深入理解可以幫助開發人員優化性能!
(瀏覽器調試工具performance會記錄每個節點的時間點、時間消耗)
流程:
1,startTime之後就要開始跳轉(redirectStart),因爲瀏覽器要判斷地址是否已經永久跳轉至新地址
2,看緩存(cache)
3,DNS解析
4,創建tcp鏈接(三次握手),如果請求是https,就要創建https鏈接,在http基礎上加一個保證數據安全的過程
5,發送數據包
6,返回數據

二, 網絡協議分層:


物理層:

定義物理設備如何傳輸數據(硬件,網卡,網線)

數據鏈路層:

在通信的實體間建立數據鏈路連接(0101之類)

網絡層:

爲數據在節點之間傳輸創建邏輯鏈路(尋找百度的服務器)

傳輸層:

向用戶提供可靠的端到端(End-to-End)服務(從自己電腦到百度鏈接之後,兩端如何傳輸數據,傳輸的方式都在這裏定義。傳輸大數據分包,分片,數據過去之後數據組裝)。傳輸層向高層屏蔽了下層數據通信的細節,http這一層不需要關心。

應用層:

爲應用軟件提供了很多服務;構建與tcp/ip協議之上;屏蔽了網絡傳輸相關細節

三, http歷史:

http/1.0:

1,增加了很多命令,POST,PUT。。。
2,增加了status code,header
3,多字符集支持、多部分發送、權限、緩存

http/1.1:

1,持久連接:http1裏面一個http請求發送就要在客戶端和服務端之間創建一個http連接,傳輸之後就關閉了,過程中有tcp三次握手,消耗性能
2,pipeline:同一個連接裏面可以發送多個請求,服務端發送回來的數據需要等待順序返回,串行。http2進行了優化,變成並行
3,增加了host和其他命令:host可以在同一臺服務器上跑多個web服務,node和java,host判斷提供哪個服務

http/2:

1,所有數據二進制傳輸
2,因爲第一點,所有pipeline可以並行操作,傳輸效率質的提升
3,頭信息壓縮以及推送等提高效率的內容,解決http1.1效率低下的問題
http1.1每次發送都要完整的頭信息,如content-type信息都是字符串, 消耗性能,壓縮之後能節約性能
推送:http請求只能客戶端先發請求,服務器接收請求;http2服務器端可以主動發送請求。比如html頁面,先獲取html信息,才能發送請求獲取css和js數據,現在http2可以主動發送數據,變串行爲並行

https:

安全版本的http1

3.1 HTTP報文

請求報文:

  • method:GET,POST(用來定義對資源的操作,GET,POST,PUT,DELETE)
  • url:具體請求資源的地方
  • 協議:http1.1和http2爲主

響應報文:

  1. 協議 狀態 狀態代表的具體含義
  2. 首部跟主體空行隔開
  3. HTTP CODE:定義服務器對請求的處理結果
    (1) 100-199:操作要持續進行,後續才返回數據
    (2) 200-299:操作成功
    (3) 300-399:操作需要重定向,用別的方式獲取數據
    (4) 400-499:操作失敗;401:沒有權限
    (5) 500-599:操作存在錯誤
    \color{red} {好的http服務是可以通過HTTP CODE來判斷結果}

3.2 URI,URL,URN

  • uri:Uniform Resource Identifier/統一資源標誌符,名詞的定義爲了識別互聯網上固定位置的資源,包含url和urn
  • url:UniForm Rsource Locator/統一資源定位符
    比如:http://user:[email protected]:80/path?query=string#hash
    默認帶80端口
    /是當前文件夾根目錄,現在/path的使用是在代碼中執行
    hash:查看文檔某個片段,作爲錨點
    此種格式就是url(http,ftp使用)
  • urn:永久統一資源定位符
    內容換地址,通過urn也能訪問到,因爲404之後url上不知道新的地址;目前沒有成熟的方案

3.3 HTTP三次握手

  • http沒有連接的概念,只有請求和響應,請求和響應都是數據包,之間要經過傳輸通道,就在tcp裏面創建的客戶端發起,服務端接收的連接,http請求是在這個連接上發送的。
  • http1中,在一個http請求時創建tcp連接,請求發送之後,服務器響應,http就斷開了
  • http1.1中,可以聲明http連接可以保持連接,
  • http2中,http請求可以併發,一個用戶對一個網頁只需要一個tcp連接

之所以需要三次握手,因爲網絡連接有消耗,數據傳輸有延時,數據可能丟失,客戶端如果沒有接收到服務端接收的信息,超時之後會發送新的連接,這樣舊的連接就不會斷開,十分浪費
windows網絡抓包工具:wiresshark

3.4 HTTP客戶端

在命令行中請求網頁數據,處處有驚喜哦:
1,curl baidu.com
2,curl www.baidu.com
3,curl -v www.baidu.com

四, 跨域CORS

實現一個簡單的跨域訪問:

node後端配置跨域
response.writeHead(200,{
    'Access-Control-Allow-Origin':'*'   //表示所有的域都可以訪問
    'Access-Control-Allow-Headers':'X-Test-Cors', //fetch預請求
    'Access-Control-Allow-Methods':'POST,PUT,Delete', //除了默認get之外預請求的類型
    'Access-Control-Max-Age':'1000', //單位是s
})
html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div>這是一個test頁面</div>
  <script>
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'http://127.0.0.1:8887/')
    xhr.send()
    console.log(11)
  </script>
</body>
</html>

server:前端服務代碼
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
  console.log('request come', request.url)
  const html = fs.readFileSync('test.html', 'utf8')
  response.writeHead(200, {
    'Content-Type': 'text/html'
  })
  response.end(html)
}).listen(8888)
console.log('server listening on 8888')

server2:後端服務代碼
const http = require('http')
http.createServer(function (request, response) {
  console.log('request come', request.url)
  response.writeHead(200, {
    'Access-Control-Allow-Origin': 'http://127.0.0.1:8888',   // 設置可以跨域的服務器,*代表全都可以
    'Access-Control-Allow-Headers': 'X-Test-Cors',
    'Access-Control-Allow-Methods': 'POST, PUT, DELETE',
    'Access-Control-Max-Age': '1000'
  })
  response.end('123')
}).listen(8887)
console.log('server listening on 8887')

\color{red}{注意:並不是設置了Access-Control-Allow-Origin就一定可以跨域:}

html:
    fetch('http://127.0.0.1:8887', {
      method: 'POST',
      headers: {
        'X-Test-Cors': '123'    // 會先向後臺發一次預請求,通過之後再發正式請求
      }
    })
    
server2:
    'Access-Control-Allow-Headers': 'X-Test-Cors',   //不配合設置就無法跨域
    'Access-Control-Allow-Methods': 'POST, PUT, DELETE', // 這裏也要和html裏面的method對應
    'Access-Control-Max-Age': '1000'  // 這個請求最長的連接時間,在這個時間段內不需要發送預請求

需要注意的幾點:

  1. CORS預請求(OPTIONS方法),method默認允許的方法:GET,POST,HEAD
  2. 默認允許的數據類型Content-Type:
    text/plain
    multipart/form-data
    application/x-www-form-urlencoded
  3. 其他請求頭限制。。。

五, HTTP請求頭以及緩存Cache-Control

重點來了!



public:http請求返回的請求經過的任何路徑(包括代理服務器,瀏覽器)都可以進行緩存
private:只有瀏覽器可以緩存
no-cache:都不能緩存

5.1 Cache-Control緩存時間:

max-age<seconds>:緩存時間
s-maxage<sceonds>:代替max-age,但是隻有在代理服務器纔會生效
max-stale<sceonds>:發起請求方主動攜帶(不是瀏覽器,應該是代碼裏寫的),max-age過期之後,如果max-stale可以代替max-age

嘗試下代碼:

html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div>這是一個test頁面</div>
  <script src="/script.js"></script>
</body>
</html>

server.js:
const http = require('http')
const fs = require('fs')

http.createServer(function (request, response) {
  console.log('request come', request.url)

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html'
    })
    response.end(html)
  }

  if (request.url === '/script.js') {
    response.writeHead(200, {
      'Content-Type': 'text/javascript',
      'Cache-Control': 'max-age=20'        //設置後,在緩存期內,客戶端會直接在本地緩存中讀取數據,即使後臺修改
    })
    response.end('console.log("script loaded")')
  }
}).listen(8888)

console.log('server listening on 8888')

5.2 Cache-Control重新驗證:

  • must-revalidate:max-age過期之後,要到服務器端驗證是否真的過期,而不能直接使用本地緩存
  • proxy-revalidate:用在緩存服務器的must-revalidate

5.3 Cache-Control其他操作:

  • no-store:和no-cache區分,no-cache是指可以在瀏覽器和代理服務器緩存,但是要去服務器驗證,服務器說可以纔可以使用;no-store是徹底的都不能存儲緩存
  • no-transform:proxy服務器使用。不允許代理服務器對返回的內容進行壓縮等改動
    注意:這些頭都只是約定,並不是強約束

5.4 Cache-Control資源驗證

  • etag等
server.js
const http = require('http')
const fs = require('fs')

http.createServer(function (request, response) {
  console.log('request come', request.url)

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html'
    })
    response.end(html)
  }

  if (request.url === '/script.js') {

    const etag = request.headers['if-none-match']
    if (etag === '777') {
        // 304表示資源未修改,瀏覽器會直接拿第一次訪問獲得的數據
      response.writeHead(304, {    
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=2000000, no-cache',
        'Last-Modified': '123',
        'Etag': '777'
      })
      response.end('mingming')
    }
    else {
        //第一次訪問時
      response.writeHead(200, {
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=2000000, no-cache',
        'Last-Modified': '123',
        'Etag': '777'
      })
      response.end('console.log("script loaded twice")')
    }
  }
}).listen(8888)

console.log('server listening on 8888')

5.5 Cookie和Session

Cookie

  • 服務端返回數據的時候通過Set-cookie的header保存在瀏覽器裏面的內容,瀏覽器保存之後下次同域請求會帶上cookie,用來識別用戶
  • max-age(多長時間)和expires(到哪個時間點)來設置過期時間
  • Secure只在https纔會發送,http沒有
  • HttpOnly:無法通過document.cookie訪問,用來避免攻擊,如CSRS攻擊,通過網頁注入腳本拿到用戶cookie到服務器拿到用戶數據
  • Set-cookie可以寫多個,有時效限制,不設置過期時間,瀏覽器關閉之後就沒有了
const http = require('http')
const fs = require('fs')

http.createServer(function (request, response) {
  console.log('request come', request.url)

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html',
      'Set-Cookie': 'id=123'    //在這裏直接給客戶端設置cookie
      'Set-Cookie': ['id=123', 'name=ming']  //設置多個cookie
      'Set-Cookie': ['id=123;max-age=4', 'name=333'] //設置時間
      'Set-Cookie': ['id=123; max-age=2', 'abc=456;domain=test.com'] 
      //同一個域名下,給其他地址設置cookie,使用demain
      //記住,不能給自己的上級域名設置,會跨域
    })
    response.end(html)
  }

}).listen(8888)
console.log('server listening on 8888')

5.6 domain

不同域的cookie不能共享,只能單獨設置,也可以通過設置domain完成二級域名恭共享cookie
演示代碼:代碼溜了

5.7 數據協商

請求:

  • Accept:指定需要的數據類型
  • Accept-Encoding:限制服務端數據壓縮類型,gzip(最流行),deflate,br(最少 ,以後可能主流);服務端將數據進行壓縮,在客戶端進行解壓,一般超過1kb的時候,傳輸的size會小於解壓之後的size
  • Accept-Language:指定返回數據類型
    User-Agent:瀏覽器相關信息(指定移動端,PC端)
user-agent: 
Mozilla/5.0                                // 老的瀏覽器默認的頭;
(Macintosh; Intel Mac OS X 10_15_5)        // 電腦系統 
AppleWebKit/537.36 (KHTML, like Gecko)     // 瀏覽器內核,KHTML渲染引擎,類似於Gecko(火狐瀏覽器引擎)
Chrome/83.0.4103.106 Safari/537.36         // 瀏覽器

返回:

Content-Type:返回的數據格式

content-type: text/html; charset=utf-8  ||    text/javascript 。。。

Content-Encoding:對應Accept-Encoding
Content-Language:對應Accept-Language

5.8 Redirect

  • 302是臨時跳轉
  • 301永久跳轉,意味着下次進入的時候url1會直接在瀏覽器更換url2,url1被緩存在瀏覽器中,disk cache,緩存時間很長,除非清緩存,服務器無法主導,所以這個使用301要非常謹慎
const http = require('http')

http.createServer(function (request, response) {
  console.log('request come', request.url)

  if (request.url === '/') {
    response.writeHead(302, {  // or 301
      'Location': '/new'
    })
    response.end()
  }
  if (request.url === '/new') {
    response.writeHead(200, {
      'Content-Type': 'text/html',
    })
    response.end('<div>this is content</div>')
  }
}).listen(8888)

console.log('server listening on 8888')

5.9 Content-Security-Policy,內容安全策略

作用:

  1. 限制資源獲取:資源從哪裏獲取,請求發到哪裏
  2. 報告資源獲取越權:獲取不應該獲取的資源時,給服務進行報告,做出調整
    default-src限制全局
    特定資源類型,限制資源範圍:connect-src,img-src,script-src。。。
const http = require('http')
const fs = require('fs')

http.createServer(function (request, response) {
  console.log('request come', request.url)

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html',
      // 'Content-Security-Policy': 'script-src \'self\'; form-action \'self\'; report-uri /report'
    })
    response.end(html)
  } else {
    response.writeHead(200, {
      'Content-Type': 'application/javascript'
    })
    response.end('console.log("loaded script")')
  }
}).listen(8888)

console.log('server listening on 8888')

html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta http-equiv="Content-Security-Policy" content="script-src 'self'; form-action 'self';">
  <title>Document</title>
</head>
<body>
  <div>This is content</div>
  <script>
    console.log('inline js')
  </script>
  <script src="test.js"></script>
  <script src="https://cdn.bootcss.com/jquery/3.3.1/core.js"></script>
</body>
</html>

六 https:

參考資源:https://coding.imooc.com/class/225.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章