内置中间件:Logger、Recovery 与 gin.New

本章解决什么问题:gin.Default() 到底默认了什么?它挂的 Logger 与 Recovery 各自负责什么、行为如何定制?本章拆解这两个内置中间件,并给出生产装配建议。

gin.New 与 gin.Default 的区别

  • gin.New():创建“裸”引擎,不含任何中间件;
  • gin.Default():等价于 gin.New() + gin.Logger() + gin.Recovery(),两者差异可在官方文档 gin-gonic.com 的快速开始与中间件章节核对。

Logger 写请求访问日志,Recovery 捕获 handler 链上的 panic 并返回 500,不让进程崩溃。开发期直接使用 Default 即可。

Logger:请求日志

Logger 默认把每条请求按“时间 | 状态码 | 耗时 | 方法 | 路径”的格式写到 gin.DefaultWriter(默认 os.Stdout)。需要同时写文件时,先替换 DefaultWriter 再做多路输出:

package main

import (
	"io"
	"os"

	"github.com/gin-gonic/gin"
)

func main() {
	f, err := os.OpenFile("access.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
	if err != nil {
		panic(err)
	}
	gin.DefaultWriter = io.MultiWriter(os.Stdout, f) // 控制台与文件双写

	r := gin.New()
	r.Use(gin.Logger(), gin.Recovery())
	r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") })
	r.Run(":8080")
}

想自定义日志格式可以用 gin.LoggerWithFormatter 替换默认格式器;gin.DisableConsoleColor() 可关闭控制台着色。

Recovery:panic 兜底

Recovery 挂在链上后,业务 handler 一旦 panic,它会把堆栈写到 gin.DefaultErrorWriter(默认 os.Stderr),并以 500 状态结束本次请求,进程继续对外服务。需要自定义输出目标时用 gin.RecoveryWithWriter(writer);要改变 500 的响应体,可换用第 13 章的自写恢复中间件。

生产装配建议

常见生产起步组合是 gin.New() + 访问日志中间件 + Recovery + 跨域中间件(第 14 章)。先用 Default 起步没问题,等需要精确控制“挂哪些中间件、什么顺序”时再切换到 New + Use。注意注册顺序:希望 Recovery 也能罩住后续中间件抛出的 panic,就把它放在链条靠前的位置。

关键点

  • Default = New + Logger + Recovery,三者行为都可分别定制或替换。
  • Logger 输出目标由 gin.DefaultWriter 决定,Recovery 的堆栈输出由 gin.DefaultErrorWriter 决定。
  • ReleaseMode 下 [GIN-debug] 调试日志消失,但 Logger 的请求日志仍会打印。
  • 中间件注册顺序即执行顺序,先注册的先进入请求。

小结

Logger 与 Recovery 是从开发到生产的两个标配,且都开放了自定义出口。下一章手写三个自定义中间件,把第 11 章的原理落到实处。

笔记加载中…