问题描述
在swagger3.0中,请求网关层https://ip:port/swagger-ui/index.html,在请求页面内任何一个服务的接口时,请求的接口 not found 。原因:我们发现页面Curl 或者 Request URL处的url地址为:https://ip:port/接口定义的路径,而缺失了服务名。我们请求网关的正确url 应该为https://ip:port/服务名/接口路径(比如:https://ip:port/order/haha —>https://ip:port//haha order 为服务名,haha为接口路径)。
原因
我们发现这是由于在网关层中添加了stripprefix配置,导致路由转发时会去掉路径中的前缀(即上面所提到的服务名)。而swagger3.0没能处理这个前缀。
swagger2.x 如何处理这个前缀
springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation 的控制器方法。会返回io.swagger.models.Swagger 实体类的json数据。源码如下:
通过debug,发现Swagger的basePath 属性,封装了路径中的前缀信息。以下是拿到basePath的方法
swagge3.0
在3.0中,控制方法变为了 springfox.documentation.oas.web.OpenApiControllerWebMvc#getDocumentation。返回给前端的实体类变成了io.swagger.v3.oas.models.OpenAPI 。
如上图,OpenAPI中缺失了 basePath。
发现swagger页面中所有的接口url的封装为 Server.url 加上 paths 中任意一个接口路径。
解决方案
在springfox.documentation.oas.web.OpenApiControllerWebMvc#getDocumentation 控制器方法返回结果之前,会遍历所有的springfox.documentation.oas.web.WebMvcOpenApiTransformationFilter,并执行其中的springfox.documentation.oas.web.OpenApiTransformationFilter#transform 方法(底层有一个默认的:WebMvcBasePathAndHostnameTransformationFilter,执行的优先级最高,主要是封装了OpenAPI中的servers属性)。
在自定义的swagger3配置类中添加如下的内部类(在OpenAPI的Server.url中 添加了在网关层去掉的前缀 ):
class BasePathAddingFilter implements WebMvcOpenApiTransformationFilter {
@Override
public OpenAPI transform(OpenApiTransformationContext<HttpServletRequest> context) {
OpenAPI openApi = context.getSpecification();
List<Server> servers = openApi.getServers();
Optional<HttpServletRequest> request = context.request();
HttpServletRequest httpServletRequest = request.get();
Enumeration<String> headers = httpServletRequest.getHeaders("X-Forwarded-Prefix");
if (headers.hasMoreElements()) {
String s = headers.nextElement();
for (Server server : servers) {
server.setUrl(String.format("%s%s", server.getUrl(), s));
}
}
return openApi;
}
@Override
public boolean supports(DocumentationType documentationType) {
return documentationType == DocumentationType.OAS_30;
}
}