Spring Cloud网关场景下能否直接向Swagger UI提供OpenAPI JSON文档?
问题背景
我有一个带动态路由的Gateway服务,希望通过Swagger UI暴露所有端点。由于路由会随Eureka中服务的注册/注销动态变化,无法使用静态YAML配置的方案。我已经完成了以下步骤:
步骤1:指定Swagger配置端点
springdoc: api-docs: enabled: false swagger-ui: enabled: true path: /swagger-ui.html config-url: /swagger-ui-config
步骤2:实现配置端点接口
package by.afinny.apigateway.controller; import by.afinny.apigateway.model.uiConfig.SwaggerUiConfig; import by.afinny.apigateway.service.SwaggerUiConfigProvider; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @RestController @RequiredArgsConstructor public class SwaggerUiConfigController { private final SwaggerUiConfigProvider configProvider; @GetMapping("/swagger-ui-config") public Mono<SwaggerUiConfig> getConfig() { return configProvider.getSwaggerUiConfig(); } }
步骤3:封装Swagger UI配置实体
package by.afinny.apigateway.model.uiConfig; import by.afinny.apigateway.model.documentedApplication.SwaggerApplication; import by.afinny.apigateway.service.SwaggerUiConfigSerializer; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import lombok.Getter; import lombok.NoArgsConstructor; import java.util.Collection; @NoArgsConstructor @Getter public class SwaggerUiConfig { @JsonProperty("urls") @JsonSerialize(contentUsing = SwaggerUiConfigSerializer.class) private Collection<SwaggerApplication> swaggerApplications; public SwaggerUiConfig(Collection<SwaggerApplication> swaggerApplications) { this.swaggerApplications = swaggerApplications; } public static SwaggerUiConfig from(Collection<SwaggerApplication> swaggerApplications) { return new SwaggerUiConfig(swaggerApplications); } }
package by.afinny.apigateway.service; import by.afinny.apigateway.model.documentedApplication.SwaggerApplication; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import lombok.SneakyThrows; import java.io.IOException; import java.text.MessageFormat; public class SwaggerUiConfigSerializer extends JsonSerializer<SwaggerApplication> { @Override @SneakyThrows public void serialize(SwaggerApplication swaggerApplication, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("url", MessageFormat.format("/{0}{1}", swaggerApplication.getName(), SwaggerApplication.SWAGGER_DOC_PATH)); jsonGenerator.writeStringField("name", swaggerApplication.getName()); jsonGenerator.writeEndObject(); } }
步骤4:配置文档转发路由
路由逻辑会将/{服务名}/v3/api-docs转发至lb://SERVICE-NAME/v3/api-docs(代码省略)
核心疑问
我在构建业务路由时已经获取并缓存了这些OpenAPI JSON文档(会实时更新),不想让Swagger UI重复执行拉取操作,能否直接向Swagger UI提供缓存的文档,而非仅告知文档地址?
可行解决方案
完全可以实现,核心思路是绕过Swagger UI默认的远程文档拉取逻辑,直接将缓存的OpenAPI JSON数据注入到Swagger UI的配置中,具体有两种实现方式:
方式一:修改后端配置端点,返回内联文档
1. 更新序列化器,直接输出缓存的文档
修改SwaggerUiConfigSerializer,不再返回url字段,而是直接返回spec字段(Swagger UI支持加载内联的OpenAPI规范):
package by.afinny.apigateway.service; import by.afinny.apigateway.model.documentedApplication.SwaggerApplication; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import lombok.SneakyThrows; import java.io.IOException; public class SwaggerUiConfigSerializer extends JsonSerializer<SwaggerApplication> { @Override @SneakyThrows public void serialize(SwaggerApplication swaggerApplication, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("name", swaggerApplication.getName()); // 直接写入缓存的OpenAPI JSON字符串,无需远程拉取 jsonGenerator.writeFieldName("spec"); jsonGenerator.writeRawValue(swaggerApplication.getCachedOpenApiJson()); jsonGenerator.writeEndObject(); } }
2. 扩展SwaggerApplication实体
在SwaggerApplication中新增字段存储缓存的文档:
package by.afinny.apigateway.model.documentedApplication; import lombok.Getter; import lombok.Setter; @Getter @Setter public class SwaggerApplication { public static final String SWAGGER_DOC_PATH = "/v3/api-docs"; private String name; // 新增:存储缓存的OpenAPI JSON文档 private String cachedOpenApiJson; }
方式二:自定义Swagger UI静态页面,直接注入文档
如果不想修改后端逻辑,可以自定义Swagger UI页面:
- 复制官方Swagger UI静态文件到项目
resources/static目录 - 修改页面初始化代码,直接传入缓存的文档数据:
const ui = SwaggerUIBundle({ urls: [ { name: "用户服务", spec: /* 直接填入缓存的用户服务OpenAPI JSON */ }, { name: "订单服务", spec: /* 直接填入缓存的订单服务OpenAPI JSON */ } ], dom_id: '#swagger-ui', deepLinking: true, // 其他Swagger UI配置 });
注意事项
- 服务注册/注销时,需同步更新缓存的OpenAPI文档,并确保Swagger UI能获取最新配置(可通过WebSocket推送或定期刷新配置端点实现)
- 直接注入
spec时需保证JSON格式正确,避免转义错误 - 若文档体积较大,建议使用方式一,避免前端页面体积过大
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

