Go 語言基礎系列(十四):網絡編程之 HTTP 編程

前言

什麼是 HTTP 呢?百度百科定義如下:

超文本傳輸協議(Hypertext Transfer Protocol,HTTP)是一個簡單的請求 - 響應協議,它通常運行在 TCP 之上。它指定了客戶端可能發送給服務器什麼樣的消息以及得到什麼樣的響應。請求和響應消息的頭以 ASCII(美國信息交換標準代碼)形式給出;而消息內容則具有一個類似 MIME(多用途互聯網郵件擴展類型)的格式

簡單來說:HTTP 是一種網頁製作所需的標記語言,不是一種編程語言。之所以稱之爲超文本,是因爲頁面需要包括的內容太多了:諸如圖片,文件,音樂等等。它是一種標準,是一個客戶端和服務端關於請求和應答的標準

所以,關於本篇的主題 HTTP 編程,我們會學習在 Golang 中怎麼快速實現客戶端和服務端的網絡編程。在客戶端和服務端編程的介紹中,我們也會穿插一些關於網絡編程相關的知識介紹

下面我們將以如上所示的兩個方面展開介紹

**   客戶端編程  **

客戶端編程是指通過客戶端發起 HTTP 請求,所以包括兩個要素:客戶端和請求

我們先通過一個示例,很快的認識一下如何通過客戶端發起一次請求

結果如下:

圖中狀態碼返回爲 200,返回的 body 體是百度首頁的 HTML 頁面定義

補充:狀態碼是表示網頁服務器超文本傳輸協議響應狀態的 3 位數字代碼:1xx:表示請求接收並在處理,爲信息性狀態碼;2xx:表示請求被成功處理,爲成功狀態碼;3xx:爲重定向狀態碼;4xx:爲客戶端錯誤狀態碼;5xx:爲服務端錯誤狀態碼

如上所示,我們通過標準庫可以很快的完成一次客戶端發起的請求,下面我們對這個過程以及結果進行分析:

首先我們看一下 Golang 標準庫裏是如何定義客戶端的:

Client 主要包括四個成員:

  1. Transport:用來指定執行一次獨立的 HTTP 請求的機制,如果爲 nil,則使用默認的 DefaultTransport

  2. CheckRedirect:用來指定處理重定向的策略

  3. Jar:Cookie 管理

  4. Timeout:指定該客戶端發起的請求的執行時間限制

下面我們再來看一下請求的定義:

Request 包括的內容較多,我們部分做一些簡單介紹:

  1. Method:請求方法

補充:示例中我們使用了 GET 請求方法:實現從服務端獲取資源;

除此之外還有 POST,HEAD,OPTIONS,PUT,DELETE,TRACE,CONNECT 請求方法:

POST : 向服務器提交或新建一個資源

HEAD:獲取響應消息報文頭

OPTIONS:查詢服務端的功能性信息

PUT:向服務端存儲資源

DELETE:在服務端刪除資源

TRACE:從服務端回顯請求信息

CONNECT:HTTP/1.1 協議中預留給能夠將連接轉爲通道方式的代理服務器

  1. URL:請求地址

補充:URL 全稱爲統一資源定位符,是互聯網上資源位置的一種表示。互聯網中的每個文件都有唯一的 URL,示例中的 http://www.baidu.com 即爲一種 URL

  1. Proto,ProtoMajor,ProtoMinor:分別爲協議版本,主版本,副版本

  2. Header:請求頭部

  3. Body:請求的 Body 體

  4. GetBody:一個可選的實現對 Body 體進行復制返回的函數

  5. ContentLength:從 Body 體讀取的字節長度

  6. Form:解析好的表單數據

  7. MultipartForm:解析好的多部分表單數據

  8. RemoteAddr:允許 HTTP 服務器或者其他軟件記錄本次請求的來源地址,通常爲了日誌使用

以上是我們關於客戶端和請求的相關介紹,接下來在示例中我們通過調用新建客戶端的 Do 方法實現請求的發送,最後對返回的數據進行顯示處理。

客戶端除了 Do 方法,還包括如下四個方法:

這四個方法都是對 Do 方法的封裝,內部均調用 Do 方法來實現具體的功能。在此,我們便不再做一一介紹,有興趣的同學可以通過源碼進行閱讀和實踐

通過上面的學習,大家基本上已經掌握瞭如何通過客戶端發起一次請求,但是有的同學可能會覺得稍顯麻煩,畢竟先得創建客戶端,然後設置請求,再發送,有沒有更簡單的方式呢?有

我們看一下 http 包裏的 Get 方法:

其實 Get 方法是客戶端 Get 方法的封裝,如下所示,而上文我們說過客戶端的 Get 方法也是 Do 方法的封裝,所以就是對上面較爲繁瑣方式的一種封裝,方便的同時失去了用戶自定義客戶端和請求內容的靈活性

以上是關於客戶端編程的介紹

**   服務端編程  **

同樣的,我們先通過一個簡單的示例觀察如何快速的創建一個服務端:

通過如上實現,我們便創建了一個監聽本機地址,端口爲 8888 的服務端。首先通過創建路由轉接器,然後將指定路徑的處理器註冊到路由器裏,之後將路由器注入 Server 並監聽 8888 端口,最後啓動服務,在瀏覽器輸入:http://localhost:8888, 結果如下:

下面我們分析一下上面的具體過程:

首先看一下服務端 Server 的定義:

我們對 Server 的成員做部分介紹:

  1. Addr:監聽的 TCP 地址

  2. Handler:調用的處理器

  3. ReadTimeout:讀取請求的最長持續時間

  4. ReadHeaderTimeout:用於讀取請求頭的時間

  5. WriteTimeout:回覆的寫入操作的最長持續時間

  6. MaxHeaderBytes:請求頭部的最大長度

接下來,我們繼續看一下路由器的定義:

如上圖所示,在路由器裏包括了一個讀寫鎖,因爲我們需要對其中存儲處理器的 map 進行操作,其中結構體 muxEntry 定義了路徑和處理器。示例中 HandleFunc 便是將處理器註冊到路由器裏的操作

同樣的,和客戶端編程一樣,大家可能覺得這樣的方式會略顯麻煩,那有沒有同樣簡便的操作方式呢?有

如上所示,通過調用 http 包裏的 HandleFunc 函數進行處理器註冊,具體是怎麼實現的呢?

由上圖可知,HandleFunc 函數里封裝了一個默認的路由器 DefaultServeMux,然後調用該處理器的處理器註冊方法 HandleFunc 將處理器註冊

接下來,進一步調用 http 包裏的 ListenAndServe 函數,那麼 ListenAndServe 如何定義的呢?

我們可以看到,ListenAndServe 函數里封裝了服務端的創建過程,然後和我們第一種的實現方式一樣,調用服務器的 ListenAndServe 方法,由於我們這裏使用的是 http 包裏默認的 DefaultServeMux 路由器,所以示例中 http.ListenAndServe 的第二個參數爲 nil

以上是關於服務端編程的內容

綜上,我們通過本篇的內容對客戶端和服務端編程進行了介紹。客戶端以 GET 方法爲例,服務端以 http 協議爲例,除此之外還有其他的客戶端請求方法以及另外的服務端 https 協議,大家可以在本篇的基礎上進一步的實踐和理解

到此關於 Golang 網絡編程之 HTTP 編程相關內容的分享就結束了~

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/aEMZ2aKM5_n2TIJb3I43xw