首頁 > 軟體

Golang實現HTTP程式設計請求和響應

2022-08-08 18:00:32

請求:

HTTP 請求報文由請求行、請求頭部、空行、請求包體4個部分組成,如下圖所示:

請求行:

請求行由方法欄位、URL 欄位 和HTTP 協定版本欄位 3個部分組成,他們之間使用空格隔開。常用的 HTTP 請求方法有 GET、POST。

GET:

  • 當用戶端要從伺服器中讀取某個資源時,使用GET 方法。GET 方法要求伺服器將URL 定位的資源放在響應報文的資料部分,回送給使用者端,即向伺服器請求某個資源。
  • 使用GET方法時,請求引數和對應的值附加在 URL 後面,利用一個問號(“?”)代表URL 的結尾與請求引數的開始,傳遞引數長度受限制,因此GET方法不適合用於上傳資料。
  • 通過GET方法來獲取網頁時,引數會顯示在瀏覽器位址列上,因此保密性很差。

POST:

  • 當用戶端給伺服器提供資訊較多時可以使用POST 方法,POST 方法向伺服器提交資料,比如完成表單資料的提交,將資料提交給伺服器處理。
  • GET 一般用於獲取/查詢資源資訊,POST 會附帶使用者資料,一般用於更新資源資訊。POST 方法將請求引數封裝在HTTP 請求資料中,而且長度沒有限制,因為POST攜帶的資料,在HTTP的請求正文中,以名稱/值的形式出現,可以傳輸大量資料。

請求頭:

請求頭部為請求報文新增了一些附加資訊,由“名/值”對組成,每行一對,名和值之間使用冒號分隔。請求頭部通知伺服器有關於使用者端請求的資訊,典型的請求頭有:

請求頭含義
User-Agent請求的瀏覽器型別
Accept使用者端可識別的響應內容型別列表,星號“ * ”用於按範圍將型別分組,用“ / ”指示可接受全部型別,用“ type/* ”指示可接受 type 型別的所有子型別
Accept-Language使用者端可接受的自然語言
Accept-Encoding使用者端可接受的編碼壓縮格式
Accept-Charset可接受的應答的字元集
Host請求的主機名,允許多個域名同處一個IP 地址,即虛擬主機
connection連線方式(close或keepalive)
Cookie儲存於使用者端擴充套件欄位,向同一域名的伺服器端傳送屬於該域的cookie

空行:

最後一個請求頭之後是一個空行,傳送回車符和換行符,通知伺服器以下不再有請求頭。

請求包體:

請求包體不在GET方法中使用,而在POST方法中使用。POST方法適用於需要客戶填寫表單的場合。與請求包體相關的最常使用的是包體型別Content-Type和包體長度Content-Length。

響應:

響應報文格式說明
HTTP 響應報文由狀態行、響應頭部、空行、響應包體4個部分組成,如下圖所示:

狀態行:

狀態行由 HTTP 協定版本欄位、狀態碼和狀態碼的描述文字3個部分組成,他們之間使用空格隔開。

狀態碼:狀態碼由三位數位組成,第一位數位表示響應的型別,常用的狀態碼有五大類如下所示:

狀態碼含義
1xx表示伺服器已接收了使用者端請求,使用者端可繼續傳送請求
2xx表示伺服器已成功接收到請求並進行處理
3xx表示伺服器要求使用者端重定向
4xx表示使用者端的請求有非法內容
5xx表示伺服器未能正常處理使用者端的請求而出現意外錯誤

常見的狀態碼舉例:

狀態碼含義
200 OK使用者端請求成功
400 Bad Request請求報文有語法錯誤
401 Unauthorized未授權
403 Forbidden伺服器拒絕服務
404 Not Found請求的資源不存在
500 Internal Server Error伺服器內部錯誤
503 Server Unavailable伺服器臨時不能處理使用者端請求(稍後可能可以)

響應頭可能包括:

響應頭含義
Location Location響應報頭域用於重定向接受者到一個新的位置
Server Server響應報頭域包含了伺服器用來處理請求的軟體資訊及其版本
Vary指示不可快取的請求頭列表
Connection連線方式

空行:

最後一個響應頭部之後是一個空行,傳送回車符和換行符,通知伺服器以下不再有響應頭部。

響應包體:

伺服器返回給使用者端的文字資訊

響應報文格式:

要想獲取響應報文,必須先傳送請求報文給web伺服器。伺服器收到並解析瀏覽器(使用者端)傳送的請求報文後,藉助http協定,回覆相對應的響應報文。可以用net/http包,建立一個最簡單的伺服器,給瀏覽器回傳送響應包。首先註冊處理常式http.HandleFunc(),設定回撥函數handler。而後繫結伺服器的監聽地址http.ListenAndserve()。這個伺服器啟動後,當有瀏覽器傳送請求,回撥函數被呼叫,會向瀏覽器回覆“hello world”作為網頁內容。當然,是按照http協定的格式進行回覆。

HTTP伺服器端實現:

Go語言標準庫內建提供了net/http包,涵蓋了HTTP使用者端和伺服器端的具體實現。使用net/http包,我們可以很方便地編寫HTTP使用者端或伺服器端的程式。

package main

import (
	"fmt"
	"net/http"
)

func main() {
	/**
	註冊回撥函數,該回撥函數會在伺服器被存取時自動被呼叫
	func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
		pattern:存取伺服器檔案位置
		handler:回撥函數名,函數必須是ResponseWriter, *Request型別作為引數
	*/
	http.HandleFunc("/itzhuzhu", myHandlerFunc)

	/**
	繫結伺服器監聽地址
	func ListenAndServe(addr string, handler Handler) error
		addr:要監聽的地址
		handler:回撥函數,為空則呼叫系統預設的回撥函數
	*/
	http.ListenAndServe("127.0.0.1:8000", nil)
}

/**
	ResponseWriter:寫給使用者端的資料內容
	Request:從使用者端讀取到的資料內容
*/
func myHandlerFunc(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("ResponseWriter Test"))
	fmt.Println("Header:", r.Header)
	fmt.Println("URL:", r.URL)
	fmt.Println("Method:", r.Method)
	fmt.Println("Host:", r.Host)
	fmt.Println("RemoteAddr:", r.RemoteAddr)
	fmt.Println("Body:", r.Body)
}

HTTP使用者端實現:

使用者端模擬瀏覽器傳送請求:

package main

import (
	"fmt"
	"net"
	"os"
)

func main() {
	// 使用者端連線伺服器
	dial, err := net.Dial("tcp", "127.0.0.1:8000")
	errFunction("net.Dial err:", err)
	defer dial.Close()

	// 模擬瀏覽器
	requstHttpHeader := "GET /itzhuzhu HTTP/1.1rnHost:127.0.0.1:8000rnrn"

	// 給伺服器傳送請求報文
	dial.Write([]byte(requstHttpHeader))

	buf := make([]byte, 1024)

	// 讀取伺服器的回覆
	read, err := dial.Read(buf)
	errFunction("dial.Read err:", err)
	fmt.Println( string(buf[:read]))
}

func errFunction(describe string, err error) {
	if err != nil {
		fmt.Println(describe, err)
		os.Exit(1)
	}
}

伺服器傳送的響應包體被儲存在Body中。可以使用它提供的Read方法來獲取資料內容。儲存至切片緩衝區中,拼接成一個完整的字串來檢視。
結束的時候,需要呼叫Body中的Close()方法關閉io。

package main

import (
	"fmt"
	"net/http"
)

func main()  {
	// 使用Get方法獲取伺服器響應包資料
	resp, err := http.Get("http://www.baidu.com")
	if err != nil {
		fmt.Println("Get err:", err)
		return
	}
	defer resp.Body.Close()

	// 獲取伺服器端讀到的資料
	fmt.Println("Status = ", resp.Status)           // 狀態
	fmt.Println("StatusCode = ", resp.StatusCode)   // 狀態碼
	fmt.Println("Header = ", resp.Header)           // 響應頭部
	fmt.Println("Body = ", resp.Body)               // 響應包體

	buf := make([]byte, 4096)         // 定義切片緩衝區,存讀到的內容
	var result string
	// 獲取伺服器傳送的封包內容
	for {
		n, err := resp.Body.Read(buf)  // 讀body中的內容。
		if n == 0 {
			fmt.Println("Body.Read err:", err)
			break
		}
		result += string(buf[:n])     // 累加讀到的資料內容
	}
	// 列印從body中讀到的所有內容
	fmt.Println("result = ", result)
}

到此這篇關於Golang實現HTTP程式設計請求和響應的文章就介紹到這了,更多相關Golang HTTP程式設計請求和響應內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com