如果我们想要网关统一代理每个服务的swagger api可以按照以下步骤实现(已我自己的服务为例)
一,在网关中配置每个服务的swagger服务路由规则
二,实现 SwaggerResourcesProvider 接口,用于重写SwaggerResource资源列表
@Component
@Primary
@AllArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {
@Autowired
private final RouteLocator routeLocator;
@Autowired
private final GatewayProperties gatewayProperties;
@Autowired
private final RouteDefinitionLocator routeDefinitionLocator;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routes = new ArrayList<>();
//取出gateway的route
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
//结合配置的route-路径(Path),和route过滤,只获取有效的route节点
routeDefinitionLocator.getRouteDefinitions().subscribe(routeDefinition -> {
if (routes.contains(routeDefinition.getId())) {
routeDefinition.getPredicates().stream()
.filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
.forEach(predicateDefinition -> {
String swaggerPattern = predicateDefinition.getArgs().get("SwaggerPattern");
if(swaggerPattern != null){
// 这里是获取路由规则里的swagger路由规则,并将每个服务的swagger地址添加到SwaggerResource
resources.add(swaggerResource(routeDefinition.getId(),
swaggerPattern
.replace("**", "v2/api-docs")
));
}
}
);
}
});
// "/documentation/"+routeDefinition.getId()+API_URI
// "/" + routeDefinition.getId() + SwaggerConstant.API_URI
return resources;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
}
三,配置swagger服务的请求跳转
/**
* 用于 swagger 的请求跳转
* */
@RestController
@RequestMapping("swagger/documentation")
public class SwaggerProxyController {
private final DiscoveryClient discoveryClient;
private final WebClient.Builder webClientBuilder;
@Lazy
@Autowired
public SwaggerProxyController(DiscoveryClient discoveryClient,
WebClient.Builder webClientBuilder){
this.discoveryClient = discoveryClient;
this.webClientBuilder = webClientBuilder;
}
/**
* 根据路由规则,所有的swagger文档接口会请求到这里,然后在这个方法里面将请求通过代理到真实的服务上去
* */
@GetMapping("{serverName}/v2/api-docs")
public Mono<String> proxy(@PathVariable("serverName") String serverName){
// 在注册中心获取服务的真实地址
List<ServiceInstance> instances = discoveryClient.getInstances(serverName);
if (!CollectionUtils.isEmpty(instances)){
ServiceInstance serviceInstance = instances.get(0);
// 对应服务的swagger请求路径
String uri = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() +"/v2/api-docs";
return webClientBuilder.build().get()
.uri(uri)
.retrieve()
.bodyToMono(String.class);
}
return null;
}
}
四,配置swagger聚合接口,访问swagger页面需要请求的接口
/**
* swagger聚合接口,swagger-ui.html需要访问的接口
*/
@RestController
@RequestMapping("/swagger-resources")
public class SwaggerResourceController {
private final SwaggerProvider swaggerProvider;
@Lazy
@Autowired
public SwaggerResourceController(SwaggerProvider swaggerProvider) {
this.swaggerProvider = swaggerProvider;
}
@RequestMapping(value = "/configuration/security")
public ResponseEntity<SecurityConfiguration> securityConfiguration() {
return new ResponseEntity<>(SecurityConfigurationBuilder.builder().build(), HttpStatus.OK);
}
@RequestMapping(value = "/configuration/ui")
public ResponseEntity<UiConfiguration> uiConfiguration() {
return new ResponseEntity<>(UiConfigurationBuilder.builder().build(), HttpStatus.OK);
}
@RequestMapping
public ResponseEntity<List<SwaggerResource>> swaggerResources() {
return new ResponseEntity<>(swaggerProvider.get(), HttpStatus.OK);
}
}