通过Spring API Gateway访问Swagger的重定向问题咨询
问题场景
我有一个运行在localhost:8080的user service微服务,以及部署在localhost:8765的网关,路由配置如下:
@Bean public RouteLocator gatewayRouter(RouteLocatorBuilder routeLocatorBuilder){ return routeLocatorBuilder .routes() .route(predicateSpec -> predicateSpec .path("/user-service/**") .filters( gatewayFilterSpec -> gatewayFilterSpec .rewritePath("/user-service/(?<segment>.*)", "/${segment}") ) .uri("lb://USER-SERVICE") ) .route(predicateSpec -> predicateSpec .path("/location-service/**") .filters( gatewayFilterSpec -> gatewayFilterSpec .rewritePath("/location-service/(?<segment>.*)", "/${segment}") ) .uri("lb://LOCATION-SERVICE") ) .build(); }
直接访问localhost:8080/swagger-ui.html时,会正常重定向到http://localhost:8080/swagger-ui/index.html#/,可正常访问Swagger。但通过API网关访问localhost:8765/user-service/swagger-ui.html时,重定向会指向网关地址http://localhost:8765/swagger-ui/index.html,而非带网关前缀的路径,导致无法正常访问Swagger界面。
解决方案
方案一:网关层面修改重定向响应头
在网关的user-service路由中添加自定义过滤器,修改重定向的Location头,补全网关的路由前缀:
.route(predicateSpec -> predicateSpec .path("/user-service/**") .filters(gatewayFilterSpec -> gatewayFilterSpec .rewritePath("/user-service/(?<segment>.*)", "/${segment}") // 处理Swagger重定向的Location头,添加网关前缀 .modifyResponseBody(String.class, String.class, (exchange, body) -> { HttpHeaders headers = exchange.getResponse().getHeaders(); if (headers.containsKey(HttpHeaders.LOCATION)) { String originalLocation = headers.getFirst(HttpHeaders.LOCATION); if (originalLocation.startsWith("/swagger-ui/")) { headers.set(HttpHeaders.LOCATION, "/user-service" + originalLocation); } } return Mono.just(body); }) ) .uri("lb://USER-SERVICE") )
该过滤器会检测响应中的Location头,若是Swagger的重定向地址,自动补上/user-service前缀,让重定向路径符合网关的路由规则。
方案二:在User Service中配置Swagger的Base URL
让Swagger生成的所有路径都带上网关的路由前缀,从根源上解决重定向地址问题。在User Service的Swagger配置类中添加Server配置:
@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.your.user.service.package")) .paths(PathSelectors.any()) .build() .servers(List.of(new Server("/user-service", "User Service via API Gateway"))); } }
配置后,Swagger返回的重定向地址会自动包含/user-service前缀,Location响应头将是http://localhost:8765/user-service/swagger-ui/index.html#/,直接匹配网关路由。
方案三:禁用Swagger自动重定向,直接返回HTML
在User Service中添加一个控制器,将/swagger-ui.html请求直接转发到/swagger-ui/index.html,避免发送重定向响应:
@Controller public class SwaggerForwardController { @GetMapping("/swagger-ui.html") public String forwardToSwaggerIndex() { return "forward:/swagger-ui/index.html"; } }
这样请求/user-service/swagger-ui.html时,服务会直接返回Swagger界面的HTML内容,不会触发重定向,也就不会出现地址错误问题。
内容的提问来源于stack exchange,提问作者Ippili Akarsh

