Как создать эффективный middleware
Составные части
Middleware обычно состоит из двух частей:
-
Первая часть выполняется один раз при инициализации middleware. Здесь вы настраиваете глобальные объекты, логику конфигурации и т.д. — всё, что нужно сделать только один раз за время жизни приложения.
-
Вторая часть выполняется при каждом запросе. Например, в middleware для базы данных вы бы внедряли глобальный объект базы данных в контекст запроса. После того как он окажется в контексте, другие middleware и ваши функции-обработчики смогут извлечь и использовать его.
func funcName(params string) gin.HandlerFunc { // <--- // This is part one // ---> // Example initialization: validate input params if err := check(params); err != nil { panic(err) }
return func(c *gin.Context) { // <--- // This is part two // ---> // Example execution per request: inject into context c.Set("TestVar", params) c.Next() }}Процесс выполнения
Рассмотрим следующий пример кода:
func main() { router := gin.Default()
router.Use(globalMiddleware())
router.GET("/rest/n/api/*some", mid1(), mid2(), handler)
router.Run()}
func globalMiddleware() gin.HandlerFunc { fmt.Println("globalMiddleware...1")
return func(c *gin.Context) { fmt.Println("globalMiddleware...2") c.Next() fmt.Println("globalMiddleware...3") }}
func handler(c *gin.Context) { fmt.Println("exec handler.")}
func mid1() gin.HandlerFunc { fmt.Println("mid1...1")
return func(c *gin.Context) {
fmt.Println("mid1...2") c.Next() fmt.Println("mid1...3") }}
func mid2() gin.HandlerFunc { fmt.Println("mid2...1")
return func(c *gin.Context) { fmt.Println("mid2...2") c.Next() fmt.Println("mid2...3") }}Согласно разделу Составные части выше, при запуске процесса Gin первая часть каждого middleware выполняется первой и выводит следующую информацию:
globalMiddleware...1mid1...1mid2...1Порядок инициализации:
globalMiddleware...1 | vmid1...1 | vmid2...1Когда вы делаете запрос — например, curl -v localhost:8080/rest/n/api/some — вторая часть каждого middleware выполняется по порядку и выводит следующее:
globalMiddleware...2mid1...2mid2...2exec handler.mid2...3mid1...3globalMiddleware...3Другими словами, порядок выполнения следующий:
globalMiddleware...2 | vmid1...2 | vmid2...2 | vexec handler. | vmid2...3 | vmid1...3 | vglobalMiddleware...3