Golang中間件的責任是可插拔且自足,其作用是:1、在處理請求的過程中,對請求進行攔截、處理或過濾,並且可以在處理請求的前後進行一些操作,例如日誌記錄、身份驗證、處理請求的參數等;2、中間件可以在程式碼結構上實現業務邏輯和處理請求的分離,使得程式碼更加清晰和易於維護;3、中間件可以被重複使用,減少了程式碼重複編寫的工作量。
本教學操作環境:windows10系統、GO 1.20.1版本、Dell G3電腦。
Golang中間件的作用
中間件主要責任就是可插拔且自足。在處理請求的過程中,對請求進行攔截、處理或過濾,並且可以在處理請求的前後進行一些操作,例如日誌記錄、身份驗證、處理請求的參數等。中間件可以在程式碼結構上實現業務邏輯和處理請求的分離,使得程式碼更加清晰和易於維護。同時,中間件可以重複使用,減少了程式碼重複編寫的工作量。
程式碼範例如下:
package main import ( "fmt" "github.com/devfeel/dotweb" ) func main() { app := dotweb.New() // App注册中间件 app.Use(NewSessionAuth()) // 开启SESSION app.HttpServer.SetEnabledSession(true) // 设置路由 输出字符串 Hello Dotweb app.HttpServer.GET("/", func(ctx dotweb.Context) error { method := ctx.Request().Method return ctx.WriteString("Hello Dotweb\n" + "Method:" + method) }) //开启服务 端口号 fmt.Println("dotweb.StartServer => 8080") err := app.StartServer(8080) fmt.Println("dotweb.StartServer error => ", err) } // SessionAuth 结构体 type SessionAuth struct { dotweb.BaseMiddlware } // Handle 处理程序 func (m *SessionAuth) Handle(ctx dotweb.Context) error { fmt.Println("SessionID = ", ctx.SessionID(), " RequestURI = ", ctx.Request().RequestURI) return m.Next(ctx) } // NewSessionAuth New func NewSessionAuth() *SessionAuth { sAuth := new(SessionAuth) return sAu }
Handle是什麼時候被呼叫的?
我們看看BaseMiddlWare的源碼:
// BaseMiddleware is the base struct, user defined middleware should extend this type BaseMiddleware struct { next Middleware excludeRouters map[string]struct{} } func (bm *BaseMiddleware) SetNext(m Middleware) { bm.next = m } func (bm *BaseMiddleware) Next(ctx Context) error { httpCtx := ctx.(*HttpContext) if httpCtx.middlewareStep == "" { httpCtx.middlewareStep = middleware_App } if bm.next == nil { if httpCtx.middlewareStep == middleware_App { httpCtx.middlewareStep = middleware_Group if len(httpCtx.RouterNode().GroupMiddlewares()) > 0 { return httpCtx.RouterNode().GroupMiddlewares()[0].Handle(ctx) } } if httpCtx.middlewareStep == middleware_Group { httpCtx.middlewareStep = middleware_Router if len(httpCtx.RouterNode().Middlewares()) > 0 { return httpCtx.RouterNode().Middlewares()[0].Handle(ctx) } } if httpCtx.middlewareStep == middleware_Router { return httpCtx.Handler()(ctx) } } else { // check exclude config if ctx.RouterNode().Node().hasExcludeMiddleware && bm.next.HasExclude() { if bm.next.ExistsExcludeRouter(ctx.RouterNode().Node().fullPath) { return bm.next.Next(ctx) } } return bm.next.Handle(ctx) } return n }
透過這個程式碼我們大概能看出:BaseMiddleware其實是一個鍊錶的node中間件組成了一個鍊錶,並且有不同的類型,有group中介軟體和普通中間件,根據目前ctx所處的處理步驟決定呼叫哪一個中間件,最後呼叫ctx的handler
自訂的middleware要繼承BaseMiddleware
並且實作handle
func (asm *ApiSignMiddleware) Handle(ctx dotweb.Context) error { if sign := ctx.Request().QueryHeader("Sign"); len(sign) <= 0 { return ctx.WriteJsonC(http.StatusBadRequest, models.Response{Err: common.ErrSignParams, Data: nil}) } else { uri := ctx.Request().RequestURI if index := strings.Index(uri, "?"); index != -1 { uri = uri[:index] } if ok := checkSign(sign, uri); !ok { return ctx.WriteJsonC(http.StatusBadRequest, models.Response{Err: common.ErrSignParams, Data: nil}) } return asm.Next(ctx) } }
這樣就可以對傳進來的Contex進行解析
分析blogserver裡面用到的middleware:
CrosMiddleware
func (cm *CrosMiddleware) Handle(ctx dotweb.Context) error { if strings.Contains(ctx.Request().RequestURI, "v1") && ctx.Request().Method != "OPTIONS" { if sign := ctx.Request().QueryHeader("Sign"); len(sign) <= 0 { return ctx.WriteJsonC(http.StatusBadRequest, models.Response{Err: common.ErrSignParams, Data: nil}) } else { uri := ctx.Request().RequestURI if index := strings.Index(uri, "?"); index != -1 { uri = uri[:index] } if ok := checkSign(sign, uri); !ok { return ctx.WriteJsonC(http.StatusBadRequest, models.Response{Err: common.ErrSignParams, Data: nil}) } return cm.Next(ctx) } } return cm.Next(ctx) }
CrosMiddleware 对uri的非参数部分调用checkSign
//验证签名 (requestUri(不含query)+secret) func checkSign(sign, uri string) bool { result := utils.Md5(uri + config.Config().SecretKey) return result == sign }
傳過來得header裡面得sign值應該跟uri 設定檔裡面的SecretKey取md5一致
以上是golang中間件有什麼作用的詳細內容。更多資訊請關注PHP中文網其他相關文章!