应通过环境变量控制swagger启用开关:代码层用os.getenv("gin_env")≠"prod"判断是否注册路由,nginx层拦截/swagger等路径,ci/cd中生产环境跳过swag init或删除docs目录。

如何用环境变量控制 Swagger 的启用开关
直接在代码里硬编码 ginSwagger.WrapHandler 是最常见也最危险的做法——它会让生产环境暴露文档,且无法动态关闭。正确做法是把 Swagger 路由注册包裹在环境判断中。
Go 本身没有运行时 profile 概念,得靠 os.Getenv("GIN_ENV") 或 os.Getenv("APP_ENV") 读取环境变量,再决定是否注册路由:
- 启动时通过
GIN_ENV=prod go run main.go设置环境 - 在
main.go或路由初始化处加判断:if os.Getenv("GIN_ENV") != "prod" { r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) } - 注意:
os.Getenv返回空字符串即为未设置,建议显式对比"prod"而非仅判空,避免测试环境误开
为什么 knife4j.production=true 在 Gin 里不生效
knife4j.production=true 是 JeecgBoot 等 Spring Boot 框架的配置项,Gin 完全不识别该配置。强行写进 app.yaml 或 .env 文件对 Gin 项目毫无作用。
Gin 项目要实现“生产禁用”,只能靠两件事:
- 代码层:不注册 Swagger 路由(如上一节)
- 部署层:Nginx 拦截路径(见下一节),这是最后一道防线
- 别指望任何第三方配置项自动生效——Gin 没有自动扫描配置文件并关掉 Swagger 的机制
Nginx 拦截 /swagger 和 /doc.html 的最小可行配置
即使代码层做了判断,仍建议加 Nginx 拦截。因为二进制部署后无法改代码,而 Nginx 配置可热重载。
以下配置足够覆盖 Gin + swag + knife4j 常见路径,且不干扰正常 API:
location ~* ^/(swagger|doc\.html|swagger-resources|v2/api-docs|v3/api-docs|webjars) {
deny all;
access_log /var/log/nginx/swagger_blocked.log;
}
关键点:
-
~*表示大小写不敏感正则匹配,避免漏掉/Swagger这类写法 -
deny all比return 403更轻量,不触发日志格式化开销 - 不要加
allow白名单——内网访问需求应由上游鉴权(如 JWT)统一处理,而非在文档路径上开后门
Swag 注释没删干净会导致文档残留
很多人以为只要不注册路由就万事大吉,但 swag 生成的 docs/docs.go 文件如果还留在构建产物里,攻击者可能直接请求 /docs/swagger.json 获取完整接口定义。
真正安全的做法是:
- 生产构建时跳过
swag init步骤(CI/CD 中根据环境变量控制) - 或构建后手动
rm -rf docs/(确保docs不被打包进二进制或 Docker 镜像) - 检查最终镜像:
docker run --rm -it your-app ls -l docs,确认目录不存在
文档生成文件比路由注册更隐蔽,也更容易被忽略。只要 docs/ 目录存在,哪怕没注册路由,静态资源仍可能被 Nginx 或其他中间件意外暴露。











