Как создать эффективный middleware
Составные части
Middleware обычно состоит из двух частей:
-
Первая часть выполняется один раз — при инициализации вашего middleware. Здесь вы настраиваете глобальные объекты, конфигурационную логику и т.д. — всё, что должно происходить только один раз за время жизни приложения.
-
Вторая часть выполняется при каждой обработке запроса. Например, в middleware для базы данных вы можете внедрить глобальный объект базы данных в контекст запроса. После этого другие middleware и функции-обработчики могут получить и использовать его.
func funcName(params string) gin.HandlerFunc { // <--- // Это первая часть // ---> // Пример инициализации: проверка входных параметров if err := check(params); err != nil { panic(err) }
return func(c *gin.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