网关层聚合Swagger接口文档的实现思路

在介绍实现思路前,要明确项目中的接口数据是怎样被渲染到 Swagger UI 页面中的。

打开项目中某个服务端 Swagger UI 页面。打开浏览器控制台中的 “Network” 面板,在页面加载过程中查看其中的请求,Swagger UI 页面中接口文档加载主要有 3 个请求,如图 9-1 所示。其中,/swagger-resources/v3/api-docs 两个请求的内容和作用对本次找出聚合 Swagger 接口文档的实现思路有一些帮助。

image 2025 04 28 13 40 47 853
Figure 1. 图9-1 接口文档页面加载过程中的请求分析

/swagger-resources 请求用于获取 Swagger 资源,其响应的内容是 Swagger 资源数组。图 9-1 中返回的资源列表只有一个,资源名称为 default,资源网址为当前项目的基础路径加上 /v3/api-docs。获取 Swagger 资源后,直接请求这个资源网址获取接口文档的 JSON 数据,如图 9-2 所示。

image 2025 04 28 13 41 29 066
Figure 2. 图9-2 接口文档详细数据的请求分析

获取这些接口数据后,就可以渲染到 Swagger UI 页面中了。

好的,Swagger UI 页面中接口文档的加载过程清晰了,步骤如下:获取页面配置→获取 Swagger 资源→根据资源 URL 获取接口文档的 JSON 数据→将接口文档的 JSON 数据渲染到页面中。

聚合 Swagger 接口文档的实现思路就是在 “获取 Swagger 资源” 这个步骤中做一些修改,让当前的 Swagger UI 页面可以获取多个 Swagger 资源。具体做法是在网关层整合 Swagger 之后,从路由配置中获取底层多个微服务实例信息,根据这些实例信息组装对应的 Swagger 页面所需的资源信息,包括资源名称、资源 URL 等。

讲完了实现思路就要来聊一聊具体的编码实现,对于 Swagger 资源处理,Swagger 底层提供了一个 SwaggerResourcesProvider 接口,这是资源处理的关键接口,其唯一的默认实现类是 springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider,在默认的情况下接口资源都会经由此类处理后返回给前端。其核心代码如下:

@Override
public List<SwaggerResource> get() {
    List<SwaggerResource> resources = new ArrayList<>();
    for (Map.Entry<String, Documentation> entry : documentationCache.all().entrySet()) {
        String swaggerGroup = entry.getKey();
        if (swagger1Available) {
            SwaggerResource swaggerResource = resource(swaggerGroup, swagger1Url);
            swaggerResource.setSwaggerVersion("1.2");
            resources.add(swaggerResource);
        }

        if (swagger2Available) {
            SwaggerResource swaggerResource = resource(swaggerGroup, swagger2Url);
            swaggerResource.setSwaggerVersion("2.0");
            resources.add(swaggerResource);
        }

        if (oas3Available) {
            SwaggerResource swaggerResource = resource(swaggerGroup, oas3Url);
            swaggerResource.setSwaggerVersion("3.0.3");
            resources.add(swaggerResource);
        }
    }
    Collections.sort(resources);
    return resources;
}

private SwaggerResource resource(
        String swaggerGroup,
        String baseUrl) {
    SwaggerResource swaggerResource = new SwaggerResource();
    swaggerResource.setName(swaggerGroup);
    swaggerResource.setUrl(swaggerLocation(baseUrl, swaggerGroup));
    return swaggerResource;
}

至此,网关聚合的实现就清晰了。在网关层加入 Swagger 依赖并重写 SwaggerResourcesProvider 接口中的 get() 方法,将需要聚合路由的子模块 Swagger 资源组装成 SwaggerResource 对象并形成数据集合,这样就可以在 Swagger UI 页面中选择对应的服务模块,调用不同服务中的 /v3/api-docs,获取具体的接口资源并展示到网关层的 Swagger UI 页面中。