問題起因:使用Zuul網(wǎng)關(guān)服務(wù)灼舍,需要整合下游系統(tǒng)的swagger,但是下游服務(wù)存在context-path配置涨薪,無法正確跳轉(zhuǎn)骑素,最后使用ZuulFilter解決。
1.Zuul整合下游swagger
首先介紹一下Zuul如何整合下游服務(wù)swagger刚夺,很好理解献丑,就是通過Zuul的swagger地址末捣,實(shí)現(xiàn)將下游服務(wù)的swagger都放入同一個頁面內(nèi),流轉(zhuǎn)圖如下:
1.1 下游服務(wù)整合swagger
這里進(jìn)行簡單介紹服務(wù)整合swagger的步驟其實(shí)就是分為兩步:
- 配置swagger
- 對api和model等進(jìn)行注釋
這里不做代碼介紹创橄,具體可以查看我的另一篇文章:https://www.dalaoyang.cn/article/21箩做,或者查看本文源碼。
這里只新建了一個服務(wù)妥畏,服務(wù)名為test-service邦邦。
1.2 Zuul聚合下游Swagger
Zuul相關(guān)配置這里不做介紹,首先配置下游服務(wù)路由咖熟,即訪問test-service/**轉(zhuǎn)發(fā)到test-service服務(wù)圃酵,配置如下:
zuul.routes.test-service.path=/test-service/**
zuul.routes.test-service.service-id=test-service
配置swagger配置文件柳畔,如下:
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("使用Swagger2構(gòu)建RESTful APIs")
.description("關(guān)注博主博客:https://www.dalaoyang.cn/")
.termsOfServiceUrl("https://www.dalaoyang.cn/")
.contact("dalaoyang")
.version("1.0")
.build();
}
}
新建文檔配置馍管,這里主要目的是為了聚合下游服務(wù)的swagger,內(nèi)容很好理解薪韩,就是講SwaggerResource賦值确沸,其中name為swagger的api文檔名,location為對應(yīng)api-docs地址俘陷,version為版本罗捎,這里利用ZuulProperties來生成對應(yīng)文檔,避免寫死代碼拉盾,完整內(nèi)容如下:
@Primary
@Component
public class DocumentConfig implements SwaggerResourcesProvider {
@Autowired
private ZuulProperties zuulProperties;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> swaggerResources = new ArrayList<>();
Map<String, ZuulProperties.ZuulRoute> routes = zuulProperties.getRoutes();
for (String serviceName : routes.keySet()) {
SwaggerResource swaggerResource = initSwaggerResource(serviceName,
"/" + serviceName + "/v2/api-docs", "1.0.0");
swaggerResources.add(swaggerResource);
}
return swaggerResources;
}
private SwaggerResource initSwaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
配置到這里桨菜,其實(shí)已經(jīng)完成了,訪問網(wǎng)關(guān)swagger如圖所示:
2.下游服務(wù)存在context-path怎么辦捉偏?
從上面其實(shí)可以了解到倒得,聚合文檔的操作,其實(shí)就是將下游服務(wù)的/v2/api-docs整合進(jìn)來夭禽,當(dāng)然霞掺,可以在本文DocumentConfig中將下游服務(wù)context-path加入其中,注意注釋階段讹躯,完整代碼如下:
@Primary
@Component
public class DocumentConfig implements SwaggerResourcesProvider {
@Autowired
private ZuulProperties zuulProperties;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> swaggerResources = new ArrayList<>();
Map<String, ZuulProperties.ZuulRoute> routes = zuulProperties.getRoutes();
for (String serviceName : routes.keySet()) {
//假設(shè)下游服務(wù)的context-path為服務(wù)名
SwaggerResource swaggerResource = initSwaggerResource(serviceName,
"/" + serviceName +"/" + serviceName + "/v2/api-docs", "1.0.0");
swaggerResources.add(swaggerResource);
}
return swaggerResources;
}
private SwaggerResource initSwaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
下游服務(wù)加入context-path配置菩彬,如下:
server.servlet.context-path=/test-service
啟動服務(wù),訪問Zuul的swagger文檔潮梯,還是可以同樣的訪問骗灶,但是測試一下在swagger請求一下下游服務(wù)api,如下
很明顯秉馏,404的原因就是因?yàn)檗D(zhuǎn)發(fā)下游服務(wù)的時(shí)候耙旦,沒有加上context-path,在本文DocumentConfig配置的方式肯定不是正確的方式沃饶,那么如何解決呢母廷?
可以加入一個ZuulFilter來進(jìn)行統(tǒng)一添加下游服務(wù)context-path轻黑,首先還原上面修改的DocumentConfig,接下來新建一個Filter繼承ZuulFilter琴昆,創(chuàng)建一個轉(zhuǎn)發(fā)前的攔截器氓鄙,將轉(zhuǎn)發(fā)地址進(jìn)行修改,也就是我們需要的加入context-pa路徑业舍,由于本文下游context-path路徑為服務(wù)名抖拦,所以案例比較簡單,內(nèi)容如下:
@Component
public class UrlPathFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 6;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
Object requestURI = requestContext.get(FilterConstants.REQUEST_URI_KEY);
Object server = requestContext.get(FilterConstants.PROXY_KEY);
String finalURI = "/" + server + requestURI;
requestContext.put(FilterConstants.REQUEST_URI_KEY, finalURI);
return null;
}
}
需要注意一點(diǎn)舷暮,這個攔截器需要在默認(rèn)ZuulFilter后執(zhí)行态罪,才能獲取requestURI和server。
再次啟動項(xiàng)目下面,就可以正常使用和訪問swagger了复颈。
3.源碼地址
Zuul地址:https://gitee.com/dalaoyang/springcloud_learn/tree/master/springcloud_swagger_zuul
Test-service地址:https://gitee.com/dalaoyang/springcloud_learn/tree/master/springcloud_swagger_service