Http協議及TCP

 

1.   瞭解部分有意義的頭部信息

頭部信息  
Catch-Control:max-age=100 靜態資源緩存100s
Content-Type,Content-Encoding 等 用來約束數據類型
Cookie    保持會話信息
CORS  實現跨域並保持安全性限制

2.    頁面如何到達瀏覽器並展現給用戶

Redirect(跳轉)--> App catch(應用緩存)-->DNS(DNS查找)-->TCP (創建TCP鏈接)-->Request(發送請求)

-->Response(接受響應)

1. redirect : 對於瀏覽器已經記錄過的301請求,直接跳轉,屬於純客戶端的行爲。

2. cache: 根據資源是否有設置cache control ,然後判斷緩存。如果超時則要重新請求緩存。

3. DNS查詢:當通過瀏覽器請求一個web頁面,瀏覽器會創建一個線程去處理這個請求,隨後開始遠程dns查找,遠程dns服務器會將輸入的URL對應的IP地址返回給瀏覽器。(DNS域名系統)

4. TCP連接: 三次握手 (HTTP請求是在TCP連接上發送的,一個TCP連接可以發送多個HTTP請求)

5. 發送請求: 數據經過代理服務器或代理服務器緩存直接讀取。瀏覽器通過連接發送一個HTTP GET請求到Web服務端。

6. 接受響應。Web服務端找到請求的資源,然後在HTTP響應中將其返回,狀態200表示響應正常。

常用狀態碼:

  • 200: 服務端成功響應
  • 301: 永久重定向
  • 302: 臨時重定向
  • 403: 請求被拒絕
  • 404: 服務端找不到請求的資源
  • 500: 處理請求時出錯
  • 503: 服務不可用
  • 504: 網關超時

   最後,瀏覽器收到頁面HTML,就開始解析並渲染頁面內容

3.   網絡協議分層

經典的五層網路模型:

 物理層:定義物理設備如何傳輸數據(電腦硬件,網卡端口,光纜...)。

數據鏈路層: 在通信的實體間建立數據鏈路連接。

網絡層:爲數據在節點之間傳輸創建邏輯鏈路。

傳輸層: 向用戶提供可靠的端對端(end-to-end)服務。更多情況下實用TCP/IP協議傳輸數據。

              定義如何傳輸數據,傳輸數據的方式。

應用層:爲應用軟件提供了很多的服務。構建於TCP協議之上。

4.   HTTP/1.1

pipeline: 可以通過聲明,在同一個連接裏發送多個請求

增加host:可以在同一臺物理服務器跑多個不同的web服務

HTTP 2 : 所有數據以二進制傳輸,同一個連接裏發送多個請求不再需要按照順序,頭信息壓縮以及推送等提高效率的功能。

推送功能(請求html的同時,可以將html中需要引用到的JavaScript文件和css文件推送到客戶端,實現html和css js文件的發送順序是閉型的,提高整體的傳輸效率)

5.  三次握手

爲了防止服務端開啓無用的連接。(網絡服務器延遲等)

瀏覽器通過與遠程web服務端的三次握手來建立一個TCP/IP請求。這個握手由瀏覽器與遠程服務端之間的SYN(標誌位),SYN-ACK,ACK消息組成。(SYN:同步序列編號)

                                                圖1  TCP 三次握手

6.   統一資源定位器  Uniform Resource Locators

scheme://host.domain:port/path/filename

說明:

  • scheme - 定義因特網服務的類型。最常見的類型是 http
    • host - 定義域主機(http 的默認主機是 www)
    • domain - 定義因特網域名,比如 runoob.com
    • :port - 定義主機上的端口號(http 的默認端口號是 80)
    • path - 定義服務器上的路徑(如果省略,則文檔必須位於網站的根目錄中)。
    • filename - 定義文檔/資源的名稱

7.   創建一個最簡單的web服務

server.js文件下創建如下內容: 

const http = require('http')

http.createServer((request, response) => {
  console.log('request', request.url)

  response.end('123')
}).listen(8888)

console.log('server listening on 8888')

啓動: node server.js

瀏覽器打開:localhost:8888, 查看內容

利用curl命令查看http報文信息

$ curl -v www.baidu.com

能得到報文頭和header的內容:

 * Rebuilt URL to: www.baidu.com/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*                                                                                                                   Trying 14.215.177.39...
* TCP_NODELAY set
* Connected to www.baidu.com (14.215.177.39) port 80 (#0)
> GET / HTTP/1.1
> Host: www.baidu.com
> User-Agent: curl/7.57.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
< Connection: Keep-Alive
< Content-Length: 2381
< Content-Type: text/html
< Date: Fri, 17 Aug 2018 05:07:47 GMT
< Etag: "588604cf-94d"
< Last-Modified: Mon, 23 Jan 2017 13:27:43 GMT
< Pragma: no-cache
< Server: bfe/1.0.8.18
< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
<
{ [1048 bytes data]
100  2381  100  2381    0     0   2381      0  0:00:01 --:--:--  0:00:01 74406

8.   跨域請求

新建server.js: 創建請求

//在8888端口中請求了一個8887端口的內容

const http = require('http')
const fs = require('fs')

http.createServer((request, response) => {  //創建請求
  console.log('request', request.url)

  const html = fs.readFileSync('test.html', 'utf8');  //同步讀取html內容
  response.writeHead(200, {
    'Content-Type': 'text/html'
  })

  response.end(html)  //響應內容
}).listen(8888)

console.log('server listening on 8888')

server2.js

const http = require('http')

http.createServer((request, response) => {
  console.log('request', request.url)

  // 允許跨域請求  寫返回的狀態
  response.writeHead(200, {
    'Access-Control-Allow-Origin': '*'
  })

  response.end('123')
}).listen(8887)

console.log('server listening on 8887')

test.html 中向8887端口發送請求:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>test</title>
</head>
<body>
  <script>
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'http://127.0.0.1:8887/')
    xhr.send()
  </script>
</body>
</html>

發送預請求:(跨域限制:保證服務端的安全)

預請求  
允許的方法 GRT、POST、HEAD
允許Content-Type

text/plain、multipart/formdata、

application/x-www-form-urlencoded

通過options請求獲得服務器的認可

server.js:

//相當於在8888端口中請求了一個8887端口的內容

const http = require('http')
const fs = require('fs')

http.createServer((request, response) => {  //創建請求
  console.log('request', request.url)

  const html = fs.readFileSync('test.html', 'utf8');  //同步讀取html內容
    response.writeHead(200, {
      'Content-Type': 'text/html'
    })
  response.end(html)  //響應內容

}).listen(8888)

console.log('server listening on 8888')

server2.js:

const http = require('http')

http.createServer((request, response) => {
  console.log('request', request.url)

  // 允許跨域請求  寫返回的狀態
  response.writeHead(200, {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'X-Test-Cors',  //允許自定義的頭
    'Access-Control-Allow-Methods': 'PUT, POST, GET',
    'Access-Control-Max-Age': '1000'
  })

  response.end('123')
}).listen(8887)

console.log('server listening on 8887')

Access-Control-Max-Age 這個響應首部表示 preflight request  (預檢請求)的返回結果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被緩存多久。

緩存Cache-Control: (哈希值用於刷新瀏覽器緩存)

可緩存性  
public 任何地方都可以對返回的內容緩存
private 只有發起請求的地方可以
no-cache 通過服務器端驗證後才能使用本地緩存
到期  
max-age=<seconds>

緩存還有多過期。      可以將max-age設置爲0,

從而讓每次訪問時緩存都進行刷新。

max-stale=<seconds> 可以使用多久的過期緩存
重新驗證  
must-revalidata 如果要提供過期的數據給客戶端,則必須向服務器驗證數據的新鮮度

緩存驗證:

緩存驗證  
Last-Modified '123'  標記此文件在服務器端最後被修改的時間
Etag '777'   用於標示URL對象是否改變

no-store: 忽略緩存

9. Cookie和Session

Cookie:1. 通過Set-Cookie設置   2. 下次請求會自動帶上  3.鍵值對,可以設置多個

屬性: 

Cookie屬性  
max-age和expires 設置過期時間
Secure 只在https的時候發送
HttpOnly 無法通過document.cookie訪問,保證用戶安全

服務端server.js:

const http = require('http')
const fs = require('fs')

http.createServer((request, response) => {  //創建請求
  console.log('request', request.url)

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8');  //同步讀取html內容
    response.writeHead(200, {
      'Content-Type': 'text/html',
      'Set-Cookie': ['abc=123; max-age=2','id=456'], //可以以數組方式傳遞多個cookie 前面一個字段的有效時間爲兩秒
      // 2s後abc=123這個數據就過期,request headers中就不會有這個信息出現
    })
    response.end(html)  //響應內容
  }

}).listen(8888)

console.log('server listening on 8888')

客戶端test.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>test</title>
</head>
<body>
  <div>content</div>
  <script src="/script.js">
    console.log(document.cookie)
  </script>
</body>
</html>

10.  數據協商: 

      客戶端請求時會聲明希望拿到的數據格式和限制,服務端根據請求頭返回不同的數據

客戶端請求

Accept

聲明想要的數據類型

[主類型]/[子類型] ,如text/html,image/jpg

Accept-Encoding

聲明進行傳輸的編碼方式

主要是數據壓縮的算法,如gzip, deflate, br

Accept-Language

聲明希望返回信息的語言

如zh-CN,zh;q=0.9(q表權重,0~1)

Usrer-Agent

聲明瀏覽器和操作系統的相關信息
服務端返回

Content-Type

聲明返回的數據格式,

如'X-Content-Type-Options':'nosniff',可阻止瀏覽器自行猜測返回數據類型而引發的安全問題。

Content-Encoding

聲明返回的編碼方式,即數據壓縮

Content-Language

聲明返回的語言

表單發送到服務器時的三種編碼方式:

enctype(編碼方式)
application/x-www-form-urlencoded 默認的編碼方式。但是在用文本的傳輸和MP3等大型文件的時候,使用這種編碼就顯得 效率低下。 
multipart/form-data 指定傳輸數據爲二進制類型,比如圖片、mp3、文件
text/plain 純文體的傳輸。空格轉換爲 “+” 加號,但不對特殊字符編碼

將表單的enctype(編碼方式)定義爲"multipart/form-data":適用於上傳文件的方式

  <form method="POST" enctype="multipart/form-data">
    <input type="text" name="name">
    <input type="password" name="psd">
    <input type="submit">
  </form>

提交表單之後:能夠在瀏覽器請求頭中得到如下信息:

Request Header:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryCoZcoYObU8Ubn5U2

boundary後的字符串用於分割表單中的每一個部分。

------WebKitFormBoundaryCoZcoYObU8Ubn5U2
Content-Disposition: form-data; name="name"

8月5
------WebKitFormBoundaryCoZcoYObU8Ubn5U2
Content-Disposition: form-data; name="psd"

sss
------WebKitFormBoundaryCoZcoYObU8Ubn5U2--

控制檯中的connection ID 代表TCP連接的ID,可以用來區分是否用的同一個連接。

connection: close, //沒有重複利用TCP連接,每次TCP請求發送完就關閉了

(HTTP請求是在TCP連接上發送的,一個TCP連接可以發送多個HTTP請求)

11.   Content Security Policy (內容安全策略)

1.  限制資源獲取   2.   報告資源獲取越權

CSP 大大增強了網頁的安全性。

兩種方法啓動CSP:

1. 一種是通過 HTTP 頭信息的Content-Security-Policy的字段

Content-Security-Policy: script-src 'self'; object-src 'none';

2. 通過網頁的<meta>標籤。

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'">

( 腳本:只信任當前域名  <object>標籤:不信任任何URL,即不加載任何資源)

只允許通過http,https方式加載src資源:

      'Content-Security-Policy': 'default-src http: https:'

只能根據本域名下的JavaScript內容進行加載:

      'Content-Security-Policy': 'default-src self'

 

 

 

 

 

 

 

 

 

 

 

 

 

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