swagger文档生成与gin中间件完全隔离,需通过注释管理(显式@router)、路由分组(公开/内部接口分离)和目录隔离实现非公开接口剔除与鉴权控制。

gin 中间件本身不感知 Swagger 文档生成逻辑,**无法自动剔除非公开接口**——这是常见误解的根源。Swagger(如 swaggo/swag)是在编译期通过注释解析生成 docs/docs.go 的静态描述文件,它和运行时的中间件完全隔离。
你真正需要的,是让「非公开接口」既不被 Swagger 收录,又在运行时不被中间件拦截(或反向:只对公开接口应用鉴权类中间件)。下面分两块说清楚怎么做、为什么、容易错在哪。
Swagger 注释必须显式标注 // @Router 才会进文档
Swaggo 不扫描所有 GET/POST 路由,只认带完整 OpenAPI 注释的 handler。没写 // @Router、// @Success 的路由,哪怕注册了也不会出现在 swagger.json 里。
所以“剔除”不是中间件的事,是注释管理的事:
- 公开 API 必须补全注释,例如:
// @Router /api/users [get] // @Success 200 {array} model.User func GetUsers(c *gin.Context) { ... } - 内部健康检查、调试端点、管理后台接口等,**不加任何
@Router注释**,它们自然不出现在 Swagger 页面中 - 如果用了
swag init -g自动扫描,确保-g指向的入口文件只包含对外暴露的 handler 文件(别把internal/admin/也塞进去)
中间件注册要按路由组分离,而非靠“识别是否公开”
你没法在中间件里判断当前请求“是否该出现在 Swagger”,因为:c.Request.URL.Path 是运行时路径,而 Swagger 文档是编译期产物,二者无映射关系。
正确做法是提前规划路由层级:
- 用
router.Group("/api")包公开接口,挂载AuthMiddleware()、RateLimitMiddleware() - 用
router.Group("/health")或router.Group("/debug")包内部接口,**不挂任何鉴权中间件** - 避免这种写法:
router.Use(AuthMiddleware()) // 全局注册 → 把 /health 也拦了
如果真想统一管控,可写个白名单校验中间件,但它是硬编码路径判断,不是“自动识别”:
func PublicOnlyMiddleware() gin.HandlerFunc {
publicPaths := map[string]bool{
"/health": true,
"/metrics": true,
"/swagger/*any": true,
}
return func(c *gin.Context) {
path := c.Request.URL.Path
for p := range publicPaths {
if strings.HasPrefix(path, p) || (strings.HasSuffix(p, "/*any") && strings.HasPrefix(path, strings.TrimSuffix(p, "/*any"))) {
c.Next()
return
}
}
// 其他路径走鉴权
AuthMiddleware()(c)
}
}
⚠️ 注意:/swagger/*any 这种通配需配合 gin.RouterGroup 的 wildcard 支持,且 swag serve 通常走独立 HTTP 服务,不经过 Gin 路由——所以这行实际意义不大,纯属混淆。
Swagger UI 静态资源路径别被中间件误杀
如果你手动注册了 Swagger UI 路由(比如用 gin-swagger),常见错误是把它挂到了受鉴权保护的路由组下:
- ❌ 错误:
apiGroup := router.Group("/api", AuthMiddleware()) apiGroup.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))→ 访问/api/swagger/index.html会 401 - ✅ 正确:
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))→ 顶层注册,不套中间件
另外确认 swaggerFiles.Handler 是从 github.com/swaggo/files 加载的,不是你自己写的 handler —— 后者容易漏掉 OPTIONS 或静态文件头,导致 UI 加载失败。











