Go?語言?net/http?包使用之HTTP?服務(wù)器、客戶端與中間件詳解
Go 語言標(biāo)準(zhǔn)庫(kù)中的net/http
包十分的優(yōu)秀,提供了非常完善的 HTTP 客戶端與服務(wù)端的實(shí)現(xiàn),僅通過幾行代碼就可以搭建一個(gè)非常簡(jiǎn)單的 HTTP 服務(wù)器。幾乎所有的 go 語言中的 web 框架,都是對(duì)已有的 http 包做的封裝與修改,因此,十分建議學(xué)習(xí)其他框架前最好先行掌握 http 包。
HTTP服務(wù)器
我們先初步介紹以下net/http
包的使用,通過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)過日志記錄,再進(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) }
這種方式是線程安全的,避免了全局變量的問題,是Go中處理請(qǐng)求間數(shù)據(jù)傳遞的推薦方式。
參考資料:
到此這篇關(guān)于Go 語言 net/http 包使用之HTTP 服務(wù)器、客戶端與中間件詳解的文章就介紹到這了,更多相關(guān)Go 語言 net/http 包使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Go語言實(shí)現(xiàn)并發(fā)處理CSV文件到數(shù)據(jù)庫(kù)
Go?語言的?goroutine?和通道(channel)非常適合用來并發(fā)地處理數(shù)據(jù),本文將通過簡(jiǎn)單示例介紹一下如何使用Go語言并發(fā)地處理?CSV?文件并將數(shù)據(jù)插入到數(shù)據(jù)庫(kù)中,感興趣的可以了解下2025-01-01go語言用八百行代碼實(shí)現(xiàn)一個(gè)JSON解析器
這篇文章主要為大家介紹了go語言用八百行代碼實(shí)現(xiàn)一個(gè)JSON解析器實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07詳解Golang互斥鎖內(nèi)部實(shí)現(xiàn)
本篇文章主要介紹了詳解Golang互斥鎖內(nèi)部實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06掌握GoLang Fiber路由和中間件技術(shù)進(jìn)行高效Web開發(fā)
這篇文章主要為大家介紹了GoLang Fiber路由和中間件進(jìn)行高效Web開發(fā),本文將深入探討 Fiber 中的路由細(xì)節(jié),學(xué)習(xí)如何創(chuàng)建和處理路由,深入了解使用路由參數(shù)的動(dòng)態(tài)路由,并掌握在 Fiber 應(yīng)用程序中實(shí)現(xiàn)中間件的藝術(shù)2024-01-01使用Go+GoQuery庫(kù)實(shí)現(xiàn)頭條新聞采集
在本文中,我們將介紹如何使用Go語言和GoQuery庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的爬蟲程序,用于抓取頭條新聞的網(wǎng)頁(yè)內(nèi)容,我們還將使用爬蟲代理服務(wù),提高爬蟲程序的性能和安全性,我們將使用多線程技術(shù),提高采集效率,最后,我們將展示爬蟲程序的運(yùn)行結(jié)果和代碼,需要的朋友可以參考下2023-10-10Golang 使用gorm添加數(shù)據(jù)庫(kù)排他鎖,for update
這篇文章主要介紹了Golang 使用gorm添加數(shù)據(jù)庫(kù)排他鎖,for update,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12利用GO語言實(shí)現(xiàn)多人聊天室實(shí)例教程
聊天室的實(shí)現(xiàn)大家應(yīng)該都遇到過,這篇文章主要給大家介紹了關(guān)于利用GO語言實(shí)現(xiàn)多人聊天室的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2018-03-03