🌮
Ginソースコードリーディング:middlewareとHandlerの関係
概要
- middlewareはビジネスロジックを処理するhandlerと同じものである、gin.Contextを引数としてうける関数である
- Requestを処理する時に、middlewareはhandler関数と一緒にgin.Context型のcontextに入れられています。
- gin.Contextのnext関数によって、handler関数スライスを順番に消化されています
コード
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.Use(func(context *gin.Context) {
fmt.Println("middleware")
fmt.Println("clientIP: ", context.ClientIP())
})
r.GET("/ping", func(c *gin.Context) {
fmt.Println("handle ping handler")
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
動作
/pingにアクセスしたら、以下のログがでます
middle ware
clientIP: ::1
handle ping handler
[GIN] 2022/12/06 - 21:28:51 | 200 | 1.0347ms | ::1 | GET "/ping"
明らかに、定義したmiddlewareの関数が先に実行され、/pingの関数は後実行されてます
main関数実行する時
- gin.EngineのUseを呼びます
- 引数はHandlerFunc
- middlewareをgroupのhandlersに入れます。
groupのhandlersはこれです。HandlerFuncのスライスです
- 続いて、gin.Engine.Getを使って、/pingのハンドラーを登録します
- HandlerFunc達のマージ
- HandlerFunc達のマージをツリーノードに登録
リクエスト来る時
- まずはgin.EngineのServerHttpに来ます。
- Contextを作成します
- handleHTTPRequest呼びます
- RequestにあるURLからツリーノードを探し出し
- handlerを処理します(重要!)
c.handlers = value.handlers
- contextのnextを呼びます
例えば、デフォルトで入れてあるlogger middlewareはcontext.nextを呼び出しています。
サンプルコードのmiddlewareは特にcontext.nextを呼び出していないから、contextのnext関数う内部で押して次のhandlerを呼び出しています
r.Use(func(context *gin.Context) {
fmt.Println("middleware")
fmt.Println("clientIP: ", context.ClientIP())
})
Discussion