内置中间件: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 章的原理落到实处。