Golang使用原生http實(shí)現(xiàn)中間件的代碼詳解
Golang原生http實(shí)現(xiàn)中間件
中間件(middleware):常被用來做認(rèn)證校驗(yàn)、審計(jì)等
大家常用的Iris、Gin等web框架,都包含了中間件邏輯。但有時(shí)我們引入該框架顯得較為繁重,本文將介紹通過golang原生http來實(shí)現(xiàn)中間件操作。全部代碼:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/middleware
1 定義http.Handler:具體中間件操作
①CORSMiddleware:允許跨域
// CORSMiddleware handles Cross-Origin Resource Sharing (CORS) responses.
func CORSMiddleware(next http.Handler) http.Handler {
fmt.Println("cors middleware....")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE")
//如果前后端需要傳遞自定義請(qǐng)求頭,需要再Access-Control-Allow-Headers中匹配(Yi-Auth-Token)
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, Yi-Auth-Token")
w.WriteHeader(http.StatusOK)
return
}
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Accept,Yi-Auth-Token")
//交給下一個(gè)中間件處理
next.ServeHTTP(w, r)
})
}
②AuthMiddleware:認(rèn)證
// AuthMiddleware simulates a simple authentication middleware.
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("auth middleware...")
//store info in ctx
token := r.Header.Get("Token")
if len(token) != 0 {
//TODO 1. check token 2. get userinfo from token
userID := "1"
ctx := context.WithValue(r.Context(), "userID", userID)
r = r.WithContext(ctx)
}
next.ServeHTTP(w, r)
})
}
③AuditMiddleware:審計(jì)操作
// AuditMiddleware simulates an audit logging middleware.
func AuditMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("audit middleware...")
next.ServeHTTP(w, r)
})
}
④SmokeHandler:具體處理操作
// SmokeHandler returns the current time as a string.
func SmokeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("smoke handle....")
_, err := w.Write([]byte(time.Now().String()))
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}
2 義中間件類型&定義中間件鏈
①type Middleware func(http.Handler) http.Handler:定義中間件
type Middleware func(http.Handler) http.Handler
②定義中間件鏈MiddlewareChain
// NewMiddlewareChain creates a new middleware chain with the given middlewares.
func NewMiddlewareChain(middlewares ...Middleware) Middleware {
return func(handler http.Handler) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
handler = middlewares[i](handler)
}
return handler
}
}
3 啟動(dòng)http服務(wù)
func RunAndServe() error {
defer func() {
if e := recover(); e != nil {
fmt.Println("err=", e)
}
}()
mux := http.NewServeMux()
// Create middleware chains for routes.
authMiddlewareChain := NewMiddlewareChain(CORSMiddleware, AuthMiddleware, AuditMiddleware)
//noAuthMiddlewareChain := NewMiddlewareChain(CORSMiddleware)
// Convert the middleware chain result to http.HandlerFunc.
smokeHandlerWrapped := func(w http.ResponseWriter, r *http.Request) {
authMiddlewareChain(http.HandlerFunc(SmokeHandler)).ServeHTTP(w, r)
}
mux.HandleFunc("/smoke", smokeHandlerWrapped)
fmt.Printf("listening on http://localhost:%d\n", 9999)
return http.ListenAndServe(":9999", mux)
}
4 測(cè)試
啟動(dòng)后端
go run main.go

2. 瀏覽器訪問http://localhost:9999/smoke

3. 后端日志打印
可以看到是最后才處理我們的業(yè)務(wù)Handler

全部代碼
package main
import (
"context"
"fmt"
"net/http"
"time"
)
type Middleware func(http.Handler) http.Handler
// CORSMiddleware handles Cross-Origin Resource Sharing (CORS) responses.
func CORSMiddleware(next http.Handler) http.Handler {
fmt.Println("cors middleware....")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE")
//如果前后端需要傳遞自定義請(qǐng)求頭,需要再Access-Control-Allow-Headers中匹配(Yi-Auth-Token)
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, Yi-Auth-Token")
w.WriteHeader(http.StatusOK)
return
}
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Accept,Yi-Auth-Token")
next.ServeHTTP(w, r)
})
}
// AuthMiddleware simulates a simple authentication middleware.
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("auth middleware...")
//store info in ctx
token := r.Header.Get("Token")
if len(token) != 0 {
//TODO 1. check token 2. get userinfo from token
userID := "1"
ctx := context.WithValue(r.Context(), "userID", userID)
r = r.WithContext(ctx)
}
next.ServeHTTP(w, r)
})
}
// AuditMiddleware simulates an audit logging middleware.
func AuditMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("audit middleware...")
next.ServeHTTP(w, r)
})
}
// SmokeHandler returns the current time as a string.
func SmokeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("smoke handle....")
_, err := w.Write([]byte(time.Now().String()))
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}
// NewMiddlewareChain creates a new middleware chain with the given middlewares.
func NewMiddlewareChain(middlewares ...Middleware) Middleware {
return func(handler http.Handler) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
handler = middlewares[i](handler)
}
return handler
}
}
func RunAndServe() error {
defer func() {
if e := recover(); e != nil {
fmt.Println("err=", e)
}
}()
mux := http.NewServeMux()
// Create middleware chains for routes.
authMiddlewareChain := NewMiddlewareChain(CORSMiddleware, AuthMiddleware, AuditMiddleware)
//noAuthMiddlewareChain := NewMiddlewareChain(CORSMiddleware)
// Convert the middleware chain result to http.HandlerFunc.
smokeHandlerWrapped := func(w http.ResponseWriter, r *http.Request) {
authMiddlewareChain(http.HandlerFunc(SmokeHandler)).ServeHTTP(w, r)
}
mux.HandleFunc("/smoke", smokeHandlerWrapped)
fmt.Printf("listening on http://localhost:%d\n", 9999)
return http.ListenAndServe(":9999", mux)
}
func main() {
RunAndServe()
}
以上就是Golang使用原生http實(shí)現(xiàn)中間件的代碼詳解的詳細(xì)內(nèi)容,更多關(guān)于Golang http中間件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
golang gopm get -g -v 無法獲取第三方庫的解決方案
這篇文章主要介紹了golang gopm get -g -v 無法獲取第三方庫的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-05-05
基于context.Context的Golang?loader緩存請(qǐng)求放大問題解決
這篇文章主要為大家介紹了基于context.Context的Golang?loader緩存請(qǐng)求放大解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
go語言實(shí)現(xiàn)聊天服務(wù)器的示例代碼
這篇文章主要介紹了go語言實(shí)現(xiàn)聊天服務(wù)器的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
golang gin 監(jiān)聽rabbitmq隊(duì)列無限消費(fèi)的案例代碼
這篇文章主要介紹了golang gin 監(jiān)聽rabbitmq隊(duì)列無限消費(fèi),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12
golang值類型轉(zhuǎn)換成[]uint8類型的操作
這篇文章主要介紹了golang值類型轉(zhuǎn)換成[]uint8類型的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-05-05
Go 類型轉(zhuǎn)化工具庫cast函數(shù)詳解
這篇文章主要介紹了Go 類型轉(zhuǎn)化工具庫cast函數(shù)詳解,cast 是在Github上開源的工具庫,就像他的名字一樣,他為我們提供了非常便捷的類型轉(zhuǎn)化的方法2022-07-07

