ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Spring Boot 3集成Knife4j 4:告别Swagger2,接口文档全攻略

Spring Boot 3集成Knife4j 4:告别Swagger2,接口文档全攻略 Spring Boot 3 发布后我身边陆续有同事升级项目几乎每个人都会在同一关卡住原来的 Swagger 页面打不开了。报错还各不相同有的直接启动失败有的页面白屏有的报Unable to infer base url。如果你也卡在这一步这篇文章就是给你准备的。我会用 Spring Boot 3 Knife4j 4.x 把接口文档完整跑起来全程不碰 Swagger 2也就是不带 springfox-swagger2 玩从依赖到配置、从注解到排错每一步都讲透。1. Swagger 2 失效的根源javax 到 jakarta 的大迁移1.1 Spring Boot 3 的一次“伤筋动骨”的变更先理清一个背景。Spring Boot 3.0 从底层做了重大调整其中影响面最大的不是 JDK 版本升到 17而是 Java EE 的命名空间从javax.*整体迁移到了jakarta.*。很多在我们看来雷打不动的老依赖都在这次迁移中被拦在了门外。听起来有点抽象我打个比方。以前所有 Java 服务端程序都在用同一套“电话薄”这里面存着 Servlet、JPA、Validation 等标准接口的调用方式这套电话薄的目录前缀叫javax。Spring Boot 3 大笔一挥把这套电话薄全部重印了目录前缀都改成了jakarta。如果你的程序还在按老目录javax.servlet去找类对不起根本找不到。Springfox 就是这套老电话薄的深度用户。它内部对javax.servlet、javax.validation这些类有强依赖Spring Boot 3 里这些类已经换了新地址Springfox 自然就成了“睁眼瞎”。这里面还有一个更现实的原因Springfox 的 GitHub 仓库已经很久没更新了。最后一个正式版本 3.0.0 停留在 2020 年社区里大量的 issue 没人处理。你不是第一个踩坑的人也不会是最后一个只是这个问题永远等不到官方修复了。1.2 老项目升级时最典型的三种报错如果你是从 Spring Boot 2 直接往 3 升级的大概率会遇到下面几种情况。第一种启动直接抛异常常见的几句包括ClassNotFoundException: javax.servlet.Filter、NoClassDefFoundError: javax/validation/ConstraintValidator。这基本就是 Springfox 依赖了老命名空间下的类类加载器找不到导致的。第二种应用能启动但访问/swagger-ui.html或者/v2/api-docs直接 404。这是因为 Springfox 在 Spring Boot 3 的自动配置机制下没有成功注册资源路径全都失效了。第三种页面能打开但是页面里的接口列表加载不出来控制台提示请求/v2/api-docs报错。这种情况说明你同时引入了多个 Swagger 相关依赖版本互相冲突。不管哪一种解决思路都一样从项目里彻底移除 springfox-swagger2 和 springfox-swagger-ui 这两个依赖然后用兼容 Spring Boot 3 的方案重新搭建。顺带提一句我知道有人会问那原来的 Swagger 注解还能用吗比如Api、ApiOperation、ApiModelProperty这一套。答案是如果你继续用 Springfox 的注解即使换了依赖也白搭因为 Springfox 已经没人维护了。正确的做法是用 OpenAPI 3 规范下的新注解也就是io.swagger.v3.oas.annotations.*这一套。后面我会专门写一节注解迁移对照照着改就行。2. 选型逻辑为什么 Spring Boot 3 项目要用 Knife4j 而不是继续 Swagger 22.1 从 Springfox 的废墟上长出来的两个方案Springfox 靠不住了市面上还有别的选择吗有主流的是两个方向。第一个方向是 springdoc-openapi。它是一个活跃维护的开源项目从 Spring Boot 3 发布没多久就完成了适配并且全面拥抱 OpenAPI 3 规范。它的做法是把接口文档的数据生成和 UI 展示分离数据部分通过/v3/api-docs这个接口输出 JSON展示部分默认提供一套 Swagger UI 页面。第二个方向就是咱们今天的主角 Knife4j。很多老同学对 Knife4j 的印象还停留在“Swagger UI 的增强皮肤”这个印象在 4.x 版本已经不完全准确了。Knife4j 4.x 的底层同样基于 springdoc-openapi等于把接口数据的解析、聚合能力全部交给 springdoc自己专注于把文档 UI 和周边体验做到极致。所以我在这里先给一个重要的认知纠正Knife4j 4.x 不是在 Swagger 2 上做增强而是在 OpenAPI 3 这条新赛道上基于 springdoc 提供了一套更符合国内开发者习惯的增强方案。2.2 三张表格看清 springfox、springdoc、Knife4j 的差别很多人在选型时犹豫不决我把三者的核心差异整理成大表格看得更清楚。对比项springfox-swagger2springdoc-openapiKnife4j 4.x规范支持OpenAPI 2Swagger 2OpenAPI 3OpenAPI 3Spring Boot 3 兼容不兼容完全兼容完全兼容维护状态已停更活跃维护活跃维护UI 地址/swagger-ui.html/swagger-ui.html/doc.htmlAPI 文档地址/v2/api-docs/v3/api-docs/v3/api-docs接口调试能力较弱一般强劲支持全局参数、离线文档文档分组支持支持支持且体验更好接口排序不支持有限支持原生支持自定义文档描述有限一般支持 Markdown 补全从表里能看出来如果你只想要一个零依赖、纯官方的方案springdoc-openapi 本身就够用了。但如果你需要给团队、给外部对接方提供一个更好用的文档站点Knife4j 的体验确实是高一档的。它好在哪里我挑几个真实场景说。文档页面支持中文界面搜索接口非常流畅接口可以自定义排序和作者标记前后端对需求的时候直接喊“张三负责的那个接口”就行调试请求支持全局参数把 token 配一次所有接口的调试请求都自动带上。这些是在 springdoc 默认 UI 上需要写不少代码才能实现的功能。2.3 标题说的“不带 swagger2 玩”具体是什么意思结合标题我想把这句话说透。以前在 Spring Boot 2 项目里整合 Knife4j典型的做法是引入knife4j-spring-boot-starter它内部依赖了 springfox-swagger2然后你还要加一个EnableSwagger2注解这样才能把 Docket 注册进去。这是 Knife4j 2.x 时代的玩法底层走的是 OpenAPI 2。Spring Boot 3 项目不能再这么干了必须改用 Knife4j 4.x 的 Jakarta 版本。新项目的依赖坐标是knife4j-openapi3-jakarta-spring-boot-starter底层不再依赖 springfox而是依赖 springdoc-openapi。与此同时代码里不需要再写EnableSwagger2因为 springdoc 的自动配置会帮你处理一切只需要显式声明一个OpenAPI的 Bean 来维护文档的基础信息。这篇文章后面所有的步骤都是在这个新的技术体系下展开的。我会在关键节点反复强调哪些旧习惯必须丢掉避免你照搬老教程踩坑。3. 整合步骤依赖、配置类、yml 一次写到位3.1 创建工程时的前置条件和依赖引入先说你手头必须具备的条件JDK 17、Spring Boot 3.x、Maven 3.6Gradle 也行不过我用 Maven 演示。如果你项目还是 JDK 8别急着升级整合先把 JDK 升上来再说Spring Boot 3 根本不支持 JDK 8。新建项目时只要勾选Spring Web这一个依赖就够了其他模块后续按需添加。然后打开pom.xml加入 Knife4j 的依赖。dependency groupIdcom.github.xiaoymin/groupId artifactIdknife4j-openapi3-jakarta-spring-boot-starter/artifactId version4.5.0/version /dependency这里有一个很多人会忽略的细节这个 starter 并不会自动帮你引入 springdoc-openapi 的全部能力所以我倾向于在项目里显式把 springdoc 的依赖也加上版本对齐 2.2.0 以上这是兼容 Spring Boot 3 的版本线。dependency groupIdorg.springdoc/groupId artifactIdspringdoc-openapi-starter-webmvc-ui/artifactId version2.2.0/version /dependency如果你只引入 knife4j 的 starter在实际运行时大概率会把 springdoc 的传递依赖也带进来但版本不受你控制一旦和你项目里的其他依赖冲突排查起来很痛苦。所以我个人习惯是把两个依赖都写上版本明确出问题也好定位。再补一句如果你的项目里已经存在 springfox-swagger2、springfox-swagger-ui 或者其他任何以io.swagger:swagger-annotations为坐标的老依赖请先全部移除。这一步不做后面启动报错是必然的。3.2 编写 OpenAPI 配置类让文档有名字有作者接下来创建一个配置类核心是注入一个OpenAPI类型的 Bean。这个 Bean 负责声明文档的元信息包括标题、描述、版本、联系人、License 等最终会渲染在 doc.html 页面的顶部区域。package com.example.demo.config; import io.swagger.v3.oas.models.ExternalDocumentation; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class Knife4jConfig { Bean public OpenAPI customOpenAPI() { return new OpenAPI() .info(new Info() .title(旺财记账系统接口文档) .description(本文档由 Knife4j 自动生成包含旺财记账系统的全部 RESTful 接口。) .version(v1.0.0) .contact(new Contact() .name(技术开发组) .email(devexample.com) .url(https://example.com)) .license(new License() .name(Apache 2.0) .url(https://www.apache.org/licenses/LICENSE-2.0))) .externalDocs(new ExternalDocumentation() .description(项目在线文档中心) .url(https://example.com/docs)); } }注意一个点OpenAPI这个类的完整包名是io.swagger.v3.oas.models.OpenAPI不是旧版的springfox.documentation.spring.web.plugins.Docket。从 Docket 迁移到 OpenAPI 之后最大的感受就是配置轻量了很多不需要再去定义那些复杂的ApiInfo、PathSelectors、RequestHandlerSelectors了。如果你的项目里有多个环境比如开发、测试、预发你可以在类上加Profile({dev, test})让这个 OpenAPI Bean 只在特定环境生效。这样生产环境不会暴露任何接口文档信息。3.3 application.yml 里的关键配置逐项拆解配置文件是整个整合过程中最容易出幺蛾子的地方。我先给一份完整配置然后逐项解释为什么这么写。server: port: 8080 springdoc: api-docs: enabled: true path: /v3/api-docs swagger-ui: enabled: true path: /swagger-ui.html packages-to-scan: com.example.demo.controller paths-to-match: - /api/** - /admin/** knife4j: enable: true setting: language: zh_cn enable-footer: false enable-footer-custom: true footer-custom-content: Copyright © 2024 旺财记账团队逐条说明。springdoc.api-docs.enabled决定是否生成接口 JSON默认就是 true建议显式写上方便日后在某个环境一键关闭。springdoc.api-docs.path是接口文档 JSON 的访问路径Spring Boot 3 时代的默认值是/v3/api-docs一般不用改。但如果你为了让接口风格统一把项目的所有接口都加了一个统一前缀比如/demo/v3/api-docs那你需要手动同步改这里。常见做法是在server.servlet.context-path设置了项目上下文路径时这个路径会自动带上上下文前缀不需要额外处理。springdoc.swagger-ui.path默认指向/swagger-ui.html。在 Knife4j 4.x 整合中这个路径主要用于兼容旧的访问习惯真正的主力 UI 地址是/doc.html这个地址由 knife4j 自己接管。springdoc.packages-to-scan是一个过滤选项。如果你的项目里有非常多无关的 Controller比如内部监控接口、回调接口它们不想出现在文档里就通过这个配置限定只扫描指定包。默认情况下不配置也没问题springdoc 会扫描整个 Spring 容器中的 Controller。springdoc.paths-to-match按路径前缀过滤。比如我只想让/api/**和/admin/**开头的接口进文档其余一律隐藏就在这里配。这个配置在实际项目中非常常用尤其是那些暴露了 actuator 端点的服务一张文档页面干干净净很重要。knife4j.enable是 Knife4j 增强功能的总开关。设置为 true 才能启用 doc.html 页面和全系列增强功能。如果你只是想用 springdoc 原生的/swagger-ui.html把它设为 false 也无所谓但我相信看完这篇文章的人不会这么做。knife4j.setting.language把默认界面语言改成中文。虽然 Knife4j 默认也会根据浏览器语言切换但直接写死成zh_cn可以避免团队里有人浏览器语言设置奇怪导致的乱码问题。knife4j.setting.enable-footer-custom配合footer-custom-content可以把页面底部的版权信息换成自己的顺带把默认的“Powered by Knife4j”去掉公司内部文档看起来更正式。3.4 启动验证doc.html 正常打开的判断标准配置完成后直接启动项目。启动日志里如果出现knife4j相关的初始化信息说明依赖加载没问题。然后浏览器访问http://localhost:8080/doc.html把 8080 换成你项目实际端口。页面打开后你会看到一个左侧是接口分组、中间是接口列表、右侧是接口详情的文档界面。如果左侧能按月分组展示 Controller接口点进去能看到参数说明和响应结构说明整个链路已经通了。在 Knife4j 4.x 里springdoc 自带的/swagger-ui.html也仍然可以访问只是样式比较朴素。我的建议是以后统一把/doc.html作为文档地址发给前端和测试同学。4. 注解实战从 Api 到 Operation 的迁移与增强4.1 注解体系变了的底层原因很多从 Swagger 2 时代过来的人最头疼的就是注解全变了。其实这不是 Knife4j 故意折腾你而是 OpenAPI 3 规范本身就把注解体系重构了。OpenAPI 3 规范不再使用Api、ApiOperation、ApiParam、ApiModelProperty这一套取而代之的是Tag、Operation、Parameter、Schema。这一改不是改名这么简单底层的数据模型完全不同了。旧注解描述接口的方式是“给一个类打标记”新注解的方式是“描述操作的每一个语义细节”。使用新注解还有一个额外的好处这些注解是 OpenAPI 规范的标准注解属于io.swagger.v3.oas.annotations.*包由 Swagger 官方维护。就算哪一天你不用 Knife4j、改用别的文档工具这套注解依然有效不会绑死在某一个框架上。下面我按 Controller、方法参数、实体类三个层面把最常用的写法过一遍。4.2 Controller 层的官方注解写法先看一个完整体面的 Controller 写法我直接贴代码。package com.example.demo.controller; import com.example.demo.common.Result; import com.example.demo.model.dto.UserCreateDTO; import com.example.demo.model.vo.UserVO; import com.github.xiaoymin.knife4j.core.annotations.ApiSupport; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.web.bind.annotation.*; Tag(name 01. 用户管理, description 用户注册、登录、资料修改等接口) RestController RequestMapping(/api/user) ApiSupport(author 张三, order 1) public class UserController { Operation(summary 用户分页查询, description 按条件分页查询用户列表支持用户名模糊搜索) GetMapping(/page) ApiOperationSupport(order 1) public ResultPageResultUserVO page( Parameter(name pageNum, description 页码从1开始, required true, example 1) RequestParam Integer pageNum, Parameter(name pageSize, description 每页条数, required true, example 10) RequestParam Integer pageSize) { // 业务代码省略 return Result.success(...); } Operation(summary 新增用户) PostMapping ApiOperationSupport(order 2) public ResultUserVO create(RequestBody Valid UserCreateDTO dto) { // 业务代码省略 return Result.success(...); } Operation(summary 根据ID获取用户详情) GetMapping(/{id}) ApiOperationSupport(order 3) public ResultUserVO getById( PathVariable Parameter(description 用户ID, required true, example 1001) Long id) { // 业务代码省略 return Result.success(...); } }我逐行说几个容易理解偏差的点。Tag里的name属性在 Knife4j 页面中显示为分组名。我习惯在名称前面加数字前缀比如01. 用户管理、02. 订单管理。为什么要加因为 Knife4j 默认按 Controller 类名的字母序排列分组加数字前缀能强制排序让文档里的模块顺序符合业务逻辑而不是字母序。Operation里的summary是接口列表里显示的一句话标题description是点进去看到的详细描述。写 summary 的时候尽量一句话说清接口功能比如“用户分页查询”就比“用户列表接口”强因为列表这个词有歧义是查询是刷新含糊不清。Parameter直接标在方法参数上描述单个入参的含义。注意example属性非常有用它会在调试区域自动填入示例值前端同学测试时不用手动输入效率提升很明显。ApiSupport和ApiOperationSupport是 Knife4j 的增强注解在类上加ApiSupport标记作者和分组排序在方法上加ApiOperationSupport标记接口在分组内的排序。这是我整篇文章里最建议你用起来的两个注解它直接提升了文档的可读性。4.3 实体类上的 Schema 注解实体类的注解主要作用于请求体和响应体的结构描述Knife4j 会根据字段名和类型自动生成示例 JSON但如果你想控制每个字段的说明文字和示例值就需要用Schema。package com.example.demo.model.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; Data Schema(description 用户信息返回对象) public class UserVO { Schema(description 用户ID, example 1001) private Long id; Schema(description 用户名, example zhangsan) private String username; Schema(description 头像地址, example https://cdn.example.com/avatar/1001.png) private String avatar; Schema(description 账号状态, example 1, allowableValues {0, 1}) private Integer status; }一个实用技巧Schema的allowableValues属性如果你不写Knife4j 根据字段类型是数字或者字符串会自动渲染一个输入框写了之后会渲染成下拉框非常直观。另外如果你有某个字段不想出现在文档里比如密码、密钥等敏感信息可以在字段上加Schema(hidden true)或者在返回 VO 里干脆不定义这个字段。很多人把返回实体直接拿数据库实体用导致文档里把用户密码哈希值都展示出来了这在真实的项目里是要被安全审计打回票的。4.4 从 Swagger 2 老注解迁移到 OpenAPI 3 的对照表如果你手里是一个需要迁移的老项目我这里整理了一份最常碰到的注解迁移对照表直接照着改就行。功能Swagger 2 注解OpenAPI 3 注解分组/模块描述Api(tags ...)Tag(name ..., description ...)接口方法描述ApiOperation(value ...)Operation(summary ..., description ...)方法参数描述ApiParamParameter实体类别名ApiModelSchema实体字段描述ApiModelPropertySchema忽略接口/字段ApiIgnoreHidden响应结构描述ApiResponsesApiResponses包名也变了注意 import还有一个细节响应注解ApiResponses在两组体系里的包名都差不多但一个是io.swagger.annotations.*另一个是io.swagger.v3.oas.annotations.responses.*类名相同包名不同。如果你 IDE 里 import 自动导入了错的包编译能过文档不生效非常隐蔽排查了好几回才总结出这个坑。5. doc.html 访问后的三大异常完整排查链路5.1 页面能打开但提示“文档请求异常”接口列表加载不出来这是我在各个技术群里看到最高频的问题。现象是/doc.html页面能打开但顶部红色横幅提示“文档请求异常”左边的接口列表一个都没有。遇到这个现象先别急着重启应用按下面的步骤定位。第一步浏览器按 F12 打开开发者工具切到 Network 面板刷新页面找到对/v3/api-docs发起的那个请求。看它的状态码。如果状态码是 404说明/v3/api-docs这个路径没有被正确路由。可能的原因有两个。第一个项目设置了server.servlet.context-path比如你的项目上下文路径是/demo那么接口文档的实际地址应该变成/demo/v3/api-docs。你访问 doc.html 的时候如果用了反向代理代理没有把上下文路径保留就会导致 404。第二个你把springdoc.api-docs.path改成了别的值和 knife4j 内部默认请求的路径对不上。如果状态码是 401 或 403那基本可以确定是被安全框架拦截了。这个问题我在 5.3 小节专门讲。如果状态码是 200但响应体不是预期的 JSON 文档结构而是你们项目自定义的Result包装对象说明你有一个全局的 ResponseBodyAdvice 在作怪。它拦截了所有 Controller 的返回把/v3/api-docs的返回也包装了一层。解决思路是在增强代码里判断请求路径遇到/v3/api-docs就跳过包装。第二步确认扫描范围。如果你在springdoc.packages-to-scan里配置了扫描包但实际的 Controller 不在这个包下面文档也会是空的。这个看起来很低级但我和同事排查过好几次最后发现是复制粘贴配置文件时把包名写错了。注意这个配置一旦设置就会完全覆盖默认的扫描路径不能和默认行为叠加。第三步看启动日志。Knife4j 和 springdoc 在启动时有日志输出比如springdoc的初始化信息会打印扫描到了哪些包、哪些 HandlerMethod。如果日志里出现了异常堆栈多半是依赖冲突。最常见的冲突来源是swagger-annotations的旧版本被其他依赖传递引入了。解决办法是在 Maven 依赖树里搜索io.swagger:swagger-annotations把老版本 exclusions 掉。5.2 访问 /v3/api-docs 返回 404 或 200 但内容是空的这个问题和上面的有关联但单独列出来因为还有一种特殊场景页面能显示接口列表但点击任意接口右侧详情区一片空白。先看直接访问接口文档 JSON 地址的情况http://localhost:8080/v3/api-docs。如果返回 404重点检查springdoc.api-docs.enabled没有被设置成 false。这种情况常见于你从网上复制了一份配置里面有enabled: false但你根本没意识到这是控制文档总开关的。如果返回 200 但 JSON 内容里paths是空对象说明 springdoc 没有扫描到任何接口。回头检查你的 Controller 类上有没有RestController或者ControllerResponseBody的组合注解。不要笑这个问题真的常见因为很多老项目里 Controller 类上只写了Controller和RequestMapping但方法上没有ResponseBody。Springfox 时代能显示是因为它的扫描逻辑在某些版本里对这类接口也能识别但 springdoc 的识别在默认情况下更严格。还有另一种情况你的接口路径前缀五花八门但你设置了springdoc.paths-to-match。这个配置的作用是“过滤”不是“添加”。比如你写的是paths-to-match: /api/**那所有不以/api开头的接口都会被隐藏。解决办法是检查你的接口路径是否符合这个前缀规则或者干脆去掉这个配置。5.3 被安全框架拦截Spring Security 6 的放行写法这是最容易被忽略但又最重要的一步。项目里一旦引入了 Spring Security、Shiro 这类权限框架默认情况下所有请求都需要认证doc.html 和数据接口自然也需要放行。在 Spring Boot 3 项目中Spring Security 已经升级到 6.x配置写法相比旧版本有一个明显变化antMatchers变成了requestMatchers并且authorizeHttpRequests取代了旧的authorizeRequests。很多网上教程还是旧的写法直接复制过来会报编译错误。这里给一份可以直接用的 Spring Security 配置片段。package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; Configuration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth - auth .requestMatchers( /doc.html, /webjars/**, /v3/api-docs/**, /swagger-ui/**, /favicon.ico ).permitAll() .anyRequest().authenticated() ) .csrf(csrf - csrf.ignoringRequestMatchers(/doc.html, /v3/api-docs/**)); return http.build(); } }有几个注意点。/webjars/**必须放行Knife4j 页面所需的静态资源都放在 webjars 路径下不放行的话 doc.html 能打开但样式全丢。/v3/api-docs/**后面的/**不能省。因为分组之后会有多个子路径比如/v3/api-docs/user、/v3/api-docs/order只放行/v3/api-docs的话分组文档依然被拦。/doc.html需要放行同时如果用了springdoc.swagger-ui.path配置对应的路径也要放行。还有一个容易踩的点Spring Security 6 默认开启了 CSRF 防护文档调试页面发 POST、DELETE 等非安全方法的请求时会被 CSRF 拦截。上面代码里我已经把/doc.html和/v3/api-docs/**的 CSRF 忽略掉了但如果你在 doc.html 的调试功能里遇到了 403 的问题别忘了回来检查这一行。如果你的项目用的是自定义拦截器HandlerInterceptor不是安全框架也要记得在addInterceptors配置里对这几类路径做excludePathPatterns放行。这种问题更隐蔽因为拦截器只拦你看得见的业务接口页面请求被拦了往往不会第一时间想到是自己写的拦截器干的。6. 上线前必须处理的三个细节关文档、分组、导出6.1 生产环境一键关闭文档开发环境里接口文档是前后端协作的利器。但一旦部署到生产环境公共网络可达的接口文档就是一个妥妥的信息泄露风险点。攻击者可以从文档页面快速摸清你的系统全貌甚至直接对着接口调试工具发起批量请求。最稳妥的做法是在生产环境配置文件中把文档彻底关掉。你不需要改代码只需要在application-prod.yml里加上两行springdoc: api-docs: enabled: false knife4j: enable: false这样生产环境下/doc.html返回 404/v3/api-docs也返回 404接口数据彻底不对外暴露。如果你连 404 都不想暴露可以在网关层或者 Nginx 层直接拦截/doc.html、/v3/api-docs、/swagger-ui/**这些路径返回一个统一的无权限页面。考虑到安全审计的要求我推荐在生产环境双重禁用应用层关闭功能网关层过滤路径。还有一个容易被忽略的点如果你们的接口文档是需要给外部客户看的建议单独部署一个文档服务只开放到测试环境而不是把所有服务都暴露出去。6.2 多分组配置按模块拆分文档当一个项目模块多了以后所有 Controller 塞在一张文档页里会变得非常长前后端同事翻起来都痛苦。Knife4j 支持多分组可以按业务模块拆开。配置方式很简单在application.yml里使用springdoc.group-configsspringdoc: group-configs: - group: user-center packages-to-scan: com.example.demo.controller.user - group: order-center packages-to-scan: com.example.demo.controller.order这个配置的含义是创建两个分组user-center分组只扫描com.example.demo.controller.user包下的接口order-center分组只扫描com.example.demo.controller.order包下的接口。配置完成并重启后再访问/doc.html页面左上角就会多出一个下拉框可以切换文档分组。同时每个分组也会对应一个独立的接口文档 JSON 地址格式是/v3/api-docs/{group}比如/v3/api-docs/user-center。这里有一个非常实用的场景你可以在网关层为每个分组配置独立的访问权限比如给“内部管理模块”的分组加上 IP 白名单而“开放平台模块”的分组走独立的鉴权逻辑。这样文档服务仍然是一个但每个分组的暴露范围完全可控。6.3 离线文档和自动生成客户端代码Knife4j 页面右上角有一个下载离线文档的入口支持导出 Markdown、Word、HTML 等格式。这在实际交付中很有用尤其是那些不常访问文档页面的外部合作伙伴你直接把离线文档发过去就行。还有一个进阶用法值得提因为 Knife4j 底层基于 OpenAPI 3所以/v3/api-docs返回的 JSON 是标准的 OpenAPI 规范文件。你可以用这个 JSON 配合 OpenAPI Generator 工具自动生成 Java、TypeScript、Go 等多种语言的客户端 SDK。我自己在给第三方公司提供开放接口时就是直接把这份 JSON 扔给对方的开发让他们用自己习惯的语言生成客户端代码。这样既省了手写接口文档对接资料的时间又保证了双方对接口定义的理解完全一致字段名、参数类型、响应结构都不会有偏差。如果你对接的团队用的是 YApi 这类接口管理平台通常也支持通过 OpenAPI 格式导入直接把 JSON 内容导入进去就能生成对应的接口列表比手工录入高效得多。最后再分享一个我个人的使用习惯在项目进入稳定期后我会把 doc.html 的地址直接配到内部知识库的固定页面里并标注“请优先使用离线文档紧急联调时再访问在线文档”。这样即使文档服务临时下线也不影响团队成员查阅。接口文档这种基础设施越稳定、越顺手团队的整体开发效率就越高。
返回列表