Go?語(yǔ)言?net/http?包使用之HTTP?服務(wù)器、客戶端與中間件詳解
Go 語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的net/http包十分的優(yōu)秀,提供了非常完善的 HTTP 客戶端與服務(wù)端的實(shí)現(xiàn),僅通過(guò)幾行代碼就可以搭建一個(gè)非常簡(jiǎn)單的 HTTP 服務(wù)器。幾乎所有的 go 語(yǔ)言中的 web 框架,都是對(duì)已有的 http 包做的封裝與修改,因此,十分建議學(xué)習(xí)其他框架前最好先行掌握 http 包。
HTTP服務(wù)器
我們先初步介紹以下net/http包的使用,通過(guò)http.HandleFunc()和http.ListenAndServe()兩個(gè)函數(shù)就可以輕松創(chuàng)建一個(gè)簡(jiǎn)單的Go web服務(wù)器,示例代碼如下:
package main
import (
"fmt"
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
func main() {
http.HandleFunc("/hello", helloHandler)
fmt.Println("Server starting on port 8080...")
http.ListenAndServe(":8080", nil)
}路由處理
http包提供了兩種路由注冊(cè)方式:
處理器函數(shù)(HandlerFunc):http.HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
http.HandleFunc("/hello", helloHandler)這種形式最為簡(jiǎn)單直接,適合處理簡(jiǎn)單的路由邏輯。http.HandleFunc內(nèi)部會(huì)將函數(shù)轉(zhuǎn)換為HandlerFunc類型,它實(shí)現(xiàn)了Handler接口。
處理器對(duì)象(Handler):http.Handle(pattern string, handler Handler)
type CounterHandler struct {
count int
}
func (h *CounterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.count++
fmt.Fprintf(w, "Visitor count: %d", h.count)
}
handler := &CounterHandler{}
http.Handle("/counter", handler)ServeMux路由
http.ServeMux是Go默認(rèn)提供的多路復(fù)用器(路由器),它實(shí)現(xiàn)了Handler接口,可以看作是一個(gè)高級(jí)的路由管理器。它的工作原理是:
- 注冊(cè)路由時(shí),將路徑模式(pattern)和處理器(handler)存儲(chǔ)在內(nèi)部映射中
- 收到請(qǐng)求時(shí),按照最長(zhǎng)匹配原則查找對(duì)應(yīng)的處理器
- 如果找不到精確匹配,會(huì)嘗試查找?guī)备艿穆窂?/li>
- 最終都找不到則返回404錯(cuò)誤
mux := http.NewServeMux()
mux.HandleFunc("/products/", productsHandler)
mux.HandleFunc("/articles/", articlesHandler)
mux.HandleFunc("/", indexHandler)這種路由設(shè)計(jì)雖然簡(jiǎn)單,但對(duì)于RESTful API和傳統(tǒng)Web應(yīng)用已經(jīng)足夠。對(duì)于更復(fù)雜的需求,可以考慮第三方路由庫(kù)如gorilla/mux。
HTTP客戶端
GET請(qǐng)求
resp, err := http.Get("https://example.com")
if err != nil {
// 處理錯(cuò)誤
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
// 處理錯(cuò)誤
}
fmt.Println(string(body))POST請(qǐng)求
data := url.Values{}
data.Set("key", "value")
resp, err := http.PostForm("https://example.com/form", data)
if err != nil {
// 處理錯(cuò)誤
}
defer resp.Body.Close()
// 處理響應(yīng)...自定義請(qǐng)求
req, err := http.NewRequest("GET", "https://example.com", nil)
if err != nil {
// 處理錯(cuò)誤
}
req.Header.Add("Authorization", "Bearer token123")
req.Header.Add("Content-Type", "application/json")
client := &http.Client{
Timeout: time.Second * 10,
}
resp, err := client.Do(req)
if err != nil {
// 處理錯(cuò)誤
}
defer resp.Body.Close()
// 處理響應(yīng)...中間件模式
中間件是構(gòu)建模塊化HTTP服務(wù)的關(guān)鍵模式。Go的中間件本質(zhì)上是處理器的包裝函數(shù),可以在不修改核心業(yè)務(wù)邏輯的情況下,添加橫切關(guān)注點(diǎn)功能。
基本中間件結(jié)構(gòu)
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// 調(diào)用下一個(gè)處理器
next.ServeHTTP(w, r)
// 記錄請(qǐng)求日志
log.Printf(
"%s %s %s %v",
r.Method,
r.URL.Path,
r.RemoteAddr,
time.Since(start),
)
})
}這種模式的工作流程是:
- 中間件接收一個(gè)處理器作為參數(shù)
- 返回一個(gè)新的處理器
- 新處理器在執(zhí)行原有邏輯前后添加額外功能
中間件鏈
多個(gè)中間件可以串聯(lián)形成處理鏈:
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !isAuthenticated(r) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/secure", secureHandler)
// 構(gòu)建中間件鏈
handler := loggingMiddleware(authMiddleware(mux))
http.ListenAndServe(":8080", handler)
}中間件的執(zhí)行順序是從外到內(nèi),即先注冊(cè)的中間件后執(zhí)行。上面的例子中,請(qǐng)求會(huì)先經(jīng)過(guò)日志記錄,再進(jìn)行認(rèn)證檢查。
上下文傳遞
中間件常用于在請(qǐng)求間傳遞值,這時(shí)應(yīng)該使用context.Context:
func requestIDMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 生成唯一請(qǐng)求ID
requestID := uuid.New().String()
// 創(chuàng)建新上下文并存儲(chǔ)請(qǐng)求ID
ctx := context.WithValue(r.Context(), "requestID", requestID)
// 設(shè)置響應(yīng)頭
w.Header().Set("X-Request-ID", requestID)
// 使用新上下文繼續(xù)處理
next.ServeHTTP(w, r.WithContext(ctx))
})
}
// 在處理器中獲取請(qǐng)求ID
func handler(w http.ResponseWriter, r *http.Request) {
requestID := r.Context().Value("requestID").(string)
fmt.Fprintf(w, "Request ID: %s", requestID)
}這種方式是線程安全的,避免了全局變量的問(wèn)題,是Go中處理請(qǐng)求間數(shù)據(jù)傳遞的推薦方式。
參考資料:
到此這篇關(guān)于Go 語(yǔ)言 net/http 包使用之HTTP 服務(wù)器、客戶端與中間件詳解的文章就介紹到這了,更多相關(guān)Go 語(yǔ)言 net/http 包使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語(yǔ)言中進(jìn)行API限流的實(shí)戰(zhàn)詳解
API?限流是控制和管理應(yīng)用程序訪問(wèn)量的重要手段,旨在防止惡意濫用、保護(hù)后端服務(wù)的穩(wěn)定性和可用性,下面我們就來(lái)看看如何在Go語(yǔ)言中具體實(shí)現(xiàn)吧2025-01-01
一文帶你了解Go語(yǔ)言中的I/O接口設(shè)計(jì)
I/O?操作在編程中扮演著至關(guān)重要的角色,它涉及程序與外部世界之間的數(shù)據(jù)交換,下面我們就來(lái)簡(jiǎn)單了解一下Go語(yǔ)言中的?I/O?接口設(shè)計(jì)吧2023-06-06
Golang?HTTP服務(wù)超時(shí)控制實(shí)現(xiàn)原理分析
這篇文章主要介紹了Golang?HTTP服務(wù)超時(shí)控制實(shí)現(xiàn)原理,HTTP服務(wù)的超時(shí)控制是保障服務(wù)高可用性的重要措施之一,由于HTTP服務(wù)可能會(huì)遇到網(wǎng)絡(luò)延遲,資源瓶頸等問(wèn)題,因此需要對(duì)請(qǐng)求進(jìn)行超時(shí)控制,以避免服務(wù)雪崩等問(wèn)題,需要的朋友可以參考下2023-05-05
go select編譯期的優(yōu)化處理邏輯使用場(chǎng)景分析
select 是 Go 中的一個(gè)控制結(jié)構(gòu),類似于用于通信的 switch 語(yǔ)句。每個(gè) case 必須是一個(gè)通信操作,要么是發(fā)送要么是接收。接下來(lái)通過(guò)本文給大家介紹go select編譯期的優(yōu)化處理邏輯使用場(chǎng)景分析,感興趣的朋友一起看看吧2021-06-06
Go語(yǔ)言的代碼組織結(jié)構(gòu)詳細(xì)介紹
這篇文章主要介紹了Go語(yǔ)言的代碼碼組織結(jié)構(gòu)詳細(xì)介紹,即Go語(yǔ)言源碼的文件結(jié)構(gòu),本文講解了包、main和main.main、os包等內(nèi)容,需要的朋友可以參考下2014-10-10
go語(yǔ)言使用Chromedp實(shí)現(xiàn)二維碼登陸教程示例源碼
這篇文章主要為大家介紹了go語(yǔ)言使用Chromedp實(shí)現(xiàn)二維碼登陸示例源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04

