Go For Web:踏入Web大門的第一步——Web 的工作方式

slowlydance2me發表於2023-04-13

前言:

本文作為解決如何透過 Golang 來編寫 Web 應用這個問題的前瞻,對 Golang 中的 Web 基礎部分進行一個簡單的介紹。目前 Go 擁有成熟的 Http 處理包,所以我們去編寫一個做任何事情的動態 Web 程式應該是很輕鬆的,接下來我們就去學習瞭解一些關於 Web 的相關基礎,瞭解一些概念,以及 Golang 是如何執行一個 Web 程式的。
文章預計分為四個部分逐步更新
2023-04-13 星期四 一更 全文共計約 3800 字 閱讀大約花費 5 分鐘


文章目錄:

  1. Web 的工作方式
  2. 用 Go 搭建一個最簡單的 Web 服務
  3. 瞭解 Golang 執行 web 的原理
  4. Golang http 包詳解(原始碼剖析)
  5. 總結

正文:

Web 的工作方式

  • 瞭解當你訪問一個網頁時,背後是如何運作的,發生了一些什麼?

    其實當你輸入網址(URL)並按下回車之後,你的瀏覽器相當於扮演了 客戶端 的角色,首先你的瀏覽器會去請求 DNS 伺服器進行域名解析,將你輸入的 URL 地址 轉化為對應的 ip 地址,透過 ip 地址 我們就可以找到對應的伺服器位置,從而進行 TCP 連線。

    連線之後,你的瀏覽器會傳送 HTTP 請求 (Request)包,服務區收到請求包之後開始從響應處理請求包,呼叫自身的服務,並返回 HTTP 響應 (Response)包。

    客戶端收到了來自服務端的響應之後開始渲染這個響應包裡的主體(body),等收到了全部的內容應答後,就會斷開與伺服器的 TCP 連線 (這裡先討論一般情況)
    如圖?
    image

而一個 Web 伺服器也被稱作 HTTP 伺服器, 它透過 http 協議與客戶端通訊。這個客戶端通常是指 Web 瀏覽器

所以 Web 伺服器的工作原理可以簡單的總結為:

  • 客戶端透過 TCP/IP 協議建立與伺服器的 TCP 連線
  • 客戶端向伺服器傳送 HTTP 協議請求包,請求伺服器裡的資源文件
  • 伺服器向客戶機傳送 HTTP 協議應答包, 如果請求的資源包含有其他動態語言的內容,伺服器就會呼叫動態語言的解析引擎負責處理這些動態內容,並將處理得到的資料返回給客戶端
  • 客戶端與服務端斷開連線。客戶端開始解釋收到的 HTML 文件,在客戶端螢幕上渲染圖形結果

以上步驟實現了一個 最簡單的 HTTP 事務,在上述情況中,客戶端與服務端的通訊非持久連線,傳送接收應答後就斷開(這裡暫時不討論 http 1.1 之後的持久連線、後文會有專門說明)

  • URL 和 DNS 解析

    剛剛我們提到了 URL,它可以用來輸入訪問網頁,那具體 URL 是個什麼東西呢?

URL 是 Uniform Resource Locator“統一資源定位符” 的英文縮寫
基本格式如下圖?
image

而 DNS 則是 Domain Name System “域名系統” 的英文縮寫,它是一種組織成 域層次結構的計算機和網路服務命名系統,它用於 TCP/IP 網路,它從事 將主機名 或者 域名轉換為實際 IP 地址的工作。可以把他理解成 URL 的“翻譯官”

工作原理如下圖?
image

我們來詳細地解釋一下 關於 DNS 的工作原理:

  1. 我們以 www.google.com 為例,在瀏覽器位址列輸入該域名,作業系統會首先檢查自己的 hosts 檔案中是否存在這個網址的對映關係,如果有,就可以直接呼叫這個 IP 地址的對映,完成域名解析
  2. 其次如果 hosts 裡沒有這個域名的對映,則查詢本地 DNS 解析器快取,看裡面有沒有這個網址的對映關係,如果有也直接呼叫
  3. 如果 hosts 和 本地 DNS 解析器快取都沒有,就會先去找 TCP/IP 引數中設定的首選 DNS 伺服器,我們可以把他叫做 本地 DNS 伺服器,此伺服器收到查詢需求時,如果要查詢的域名,包含在本地配置區域的資源中,就將解析結果返回給客戶端,完成域名解析,該解析具有權威性
  4. 如果要查詢的域名,本地 DNS 伺服器配置區域資源沒有,但是該伺服器卻快取了此網址的對映關係,則也可以呼叫完成解析,但是該解析不具有權威性
  5. 如果本地 DNS 伺服器本地區域資原始檔以及快取都沒有該對映,則根據本地 DNS 伺服器的設定(是否設定轉發器)進行查詢,如果未用轉發模式, 本地DNS 就把請求傳送至 “根 DNS 伺服器” “根 DNS 伺服器”收到請求後會判斷這個域名是誰來授權管理(本例子為.com),並會返回一個負責該頂級域名伺服器的一個 IP。本地 DNS 伺服器 收到 IP 資訊後,將會聯絡 負責管理 .com 域的這臺伺服器。這臺伺服器收到請求後,如果自己無法解析,它就會找管理 .com 域的下一級 DNS 伺服器地址(這裡是 google.com)並把它的 IP 給本地 DNS 伺服器。當本地 DNS 伺服器收到這個地址後,就會找 google.com 域伺服器,重複上面的操作,進行查詢,直到找到(www.goole,com)為止
  6. 如果是轉發模式,則此 DNS 伺服器就會把請求轉發至上一級 DNS 伺服器,由上一級伺服器進行解析,上一級如果不能解析,就找根伺服器,或者轉發請求給上上級伺服器,如此迴圈,直到找到(www.goole,com)為止

無論是轉發模式還是非轉發模式,是轉發給上一級還是直接找根 DNS ,最後都是把 結果返回給 本地 DNS 伺服器,由此 DNS伺服器再返回給 我們的瀏覽器(客戶端)

流程圖如下?
image

基於上面的步驟,瀏覽器最終透過 DNS 伺服器獲得的是 IP 地址,所以瀏覽器(客戶端)發起請求的時候是透過 IP 地址 來和 伺服器 進行資訊通訊的

  • HTTP 協議詳解

HTTP 協議當然是 Web 伺服器工作的核心,所以我們接下來具體詳細地瞭解清楚一下 HTTP 協議是怎麼發揮作用的

  • HTTP 協議 是一種能讓 Web 伺服器與瀏覽器(客戶端)透過 Internet 進行傳送和接受資料 動作 的一個協議,它建立在 TCP 協議之上,一般會採用 TCP 的 80 埠。它是一個標準的 “請求-響應協議” 即 客戶端發出請求,服務端收到請求返回響應。

  • 在 HTTP 協議中,客戶端總是要透過建立一個連線與傳送一個 HTTP 請求來發起一個事務。而伺服器不能主動去與客戶端聯絡,也不能給客戶端發出一個回撥連線,只能被動監聽。

  • 客戶端與服務端都可以自行提前中斷一個連線,例如,當瀏覽器下載一個檔案時,你可以隨時透過點選“暫停”按鈕來中斷檔案的下載,關閉與伺服器的 HTTP 連線。

  • HTTP 協議是無狀態的,同一個客戶端的這一次請求與上次請求之間沒有對應關係,對 HTTP 伺服器來說,它並不知道這兩個請求是否來自同一個客戶端。當然對於需要解決這個問題的情況我們可以使用 "Cookie"機制來維護連線的可持續狀態

  • 正因為 HTTP 協議是建立在 TCP 協議之上的,所以 TCP 攻擊一樣會影響 HTTP 的通訊,例如常見的針對 TCP 的攻擊:SYN Flood (比較流行的一種 Dos 拒絕服務攻擊 和 Ddos 分散式拒絕服務攻擊)就是透過利用 TCP 協議的缺陷,傳送了大量的偽造 TCP 連線請求從而使得被攻擊的伺服器資源耗盡(CPU 滿負荷或者記憶體不足)

接下來我們分別看看 HTTP 協議的 請求包和響應包

HTTP 請求包 (瀏覽器/客戶端 資訊)

我們可以使用 F12 檢視一些內容,例如 Request 包的結構:
Request 包分為三部分,第一部分叫 Request line (請求行),第二部分是 Request header (請求頭),第三部分是 body(主體),header 和 body 之間會有個空行隔開
請求包的例項圖?
image

HTTP 協議定義了很多與伺服器互動的請求方法,最基礎的四種是:GET\POST\PUT\DELETE,一個 URL 地址用於描述一個網路上的請求資源,而 HTTP 中的這四個操作就分別對應對這個資源的查改增刪4個操作

這四個操作中最熟悉和常用的是 GET 和 POST 。
GET 一般用於獲取/查詢資源資訊
POST 一般用於更新資源資訊
GET 與 POST 的區別:

  1. GET 方法提交的資料會放在 URL 後面,使用 ? 分割 URL 和 傳輸的資料,引數之間以 & 相連
  2. POST 方法則是把提交的資料放在 HTTP 包的 body 中
  3. GET能提交的資料大小會因為瀏覽器對於 URL 的長度限制而有所限制
  4. POST 方法提交的資料不會有限制
  5. GET 方法提交資料會帶來某些安全問題,例如:在使用者的登入介面,如果使用 GET 方法提交資料,使用者的賬號和密碼就會出現在 URL 上面,如果頁面被快取或者其他人可以訪問機器,就可以額從歷史記錄中獲得該使用者的賬號和密碼!

關於 GET 與 POST 之間更詳細的比較可參考我的另一篇 blog?
GET 和 POST 到底有什麼區別?

HTTP 響應包(伺服器資訊)

HTTP 的 response 包的結構如下圖?
image
image

和上面看到的請求包類似,response 響應包的第一行叫做 ”狀態行“,由 HTTP 協議版本號、狀態碼、狀態訊息 三部分組成
狀態碼的作用是告訴 HTTP 客戶端(瀏覽器),HTTP 伺服器是否產生了預期的 Response。
在 HTTP 1.1 協議中定義了 5 類 狀態碼,每個狀態碼由三位數字組成,首位表示類別:

  • 1xx 提示資訊:表示請求被成功接受,繼續處理
  • 2xx 成功:表示請求已被成功接受
  • 3xx 重定向:表示要完成這個請求必須進行更進一步的處理
  • 4xx 客戶端錯誤:客戶端的語法錯誤或者請求無法實現
  • 5xx 服務端錯誤:伺服器未能實現合法的請求

常見的狀態有:200 :正常資訊、302:跳轉、404 not found 等等

Tips: 持續連線 與 非持續連線(協議無狀態/keep-alive)

無狀態是指協議對於事物處理沒有記憶能力,伺服器不知道客戶端是什麼狀態,體現在開啟一個伺服器的網頁和你之前開啟這個伺服器的網頁之間沒有任何聯絡

HTTP 協議就是典型的無狀態的面向連線的協議,雖然是無狀態但是它是面向連線的協議,所以千萬不要說 HTTP 使用的是 UDP (面向無連線)的協議了!!!
無狀態不代表不能保持TCP連線(只要不斷開連線我就不管你什麼狀態不狀態的)
從 HTTP 1.1 開始,預設都開啟了 叫做 Keep-Alive 的保持連線的特性,也就是當一個網頁開啟完成之後,客戶端和伺服器之間用於傳輸 HTTP 資料的 TCP 連線不會關閉,如果客戶端再次訪問這個伺服器上的網頁,會繼續使用這一條已經建立的 TCP 連線

當然 Keep-ALive 不會永久保持連線,它會有一個保持時間上限,你可以自行設定

如果你嘗試去檢查(F12)訪問任意一個網址
透過分析整個 URL 請求的通訊過程,你會發現:
image
在所有的請求中不止一個 URL 請求,還會有很多其他的如靜態檔案的資源請求
這其實是瀏覽器自帶的功能之一,第一次請求 url ,伺服器端返回的是 HTML 頁面,然後瀏覽器會開始渲染這個頁面,但是當解析到 HTML DOM裡面的圖片連線、css指令碼和js指令碼的連線的時候,瀏覽器就會自動地發起一個請求靜態資源的 HTTP 請求,去獲取相應的資源並渲染,最終將所有資源整合完整地展現出來

在網頁最佳化中就會有一項措施,就是利用減少 HTTP 請求次數(把儘量多的css 和 js 資源合併)減少網頁請求靜態資源的次數,來提高網頁的載入速度,減輕伺服器的壓力

總結

  • 在這一部分,我們初步認識了 Web 的工作方式,並對一些基礎的計算機網路相關知識有了進一步瞭解,特別是對於 基於 TCP 協議的 HTTP 協議,以及該協議如何在整個 客戶端-服務端 中運作。
  • 當我們知道了 Web 就是一個基於 HTTP 協議的的一個服務的時候,我們就可以做好準備,去嘗試在 Go 語言中體會如何搭建一個可以執行的 Web 服務了。

關於 Golang 基礎部分 以及 計算機網路部分讀者可以參閱我的往期 blog?
Goalng:基礎複習一遍過

漫談計算機網路:網路層 ------ 重點:IP協議與網際網路路由選擇協議

以上

看完記得留下一個?

相關文章