1. 程式人生 > 程式設計 >Zuul整合Swagger,使用ZuulFilter解決下游服務context-path

Zuul整合Swagger,使用ZuulFilter解決下游服務context-path

問題起因:使用Zuul閘道器服務,需要整合下游系統的swagger,但是下游服務存在context-path配置,無法正確跳轉,最後使用ZuulFilter解決。

1.Zuul整合下游swagger

首先介紹一下Zuul如何整合下游服務swagger,很好理解,就是通過Zuul的swagger地址,實現將下游服務的swagger都放入同一個頁面內,流轉圖如下:

1.1 下游服務整合swagger

這裡進行簡單介紹服務整合swagger的步驟其實就是分為兩步:

  1. 配置swagger
  2. 對api和model等進行註釋

這裡不做程式碼介紹,具體可以檢視我的另一篇文章:www.dalaoyang.cn/article/21

,或者檢視本文原始碼。

這裡只新建了一個服務,服務名為test-service。

1.2 Zuul聚合下游Swagger

Zuul相關配置這裡不做介紹,首先配置下游服務路由,即訪問test-service/**轉發到test-service服務,配置如下:

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構建RESTful APIs") .description("關注博主部落格:https://www.dalaoyang.cn/") .termsOfServiceUrl("https://www.dalaoyang.cn/"
) .contact("dalaoyang") .version("1.0") .build(); } } 複製程式碼

新建檔案配置,這裡主要目的是為了聚合下游服務的swagger,內容很好理解,就是講SwaggerResource賦值,其中name為swagger的api檔名,location為對應api-docs地址,version為版本,這裡利用ZuulProperties來生成對應檔案,避免寫死程式碼,完整內容如下:

@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;
    }
}
複製程式碼

配置到這裡,其實已經完成了,訪問閘道器swagger如圖所示:

2.下游服務存在context-path怎麼辦?

從上面其實可以瞭解到,聚合檔案的操作,其實就是將下游服務的/v2/api-docs整合進來,當然,可以在本文DocumentConfig中將下游服務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()) {
            //假設下游服務的context-path為服務名
            SwaggerResource swaggerResource = initSwaggerResource(serviceName,"/" + serviceName +"/" + serviceName + "/v2/api-docs",String version) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion(version);
        return swaggerResource;
    }
}
複製程式碼

下游服務加入context-path配置,如下:

server.servlet.context-path=/test-service
複製程式碼

啟動服務,訪問Zuul的swagger檔案,還是可以同樣的訪問,但是測試一下在swagger請求一下下游服務api,如下

很明顯,404的原因就是因為轉發下游服務的時候,沒有加上context-path,在本文DocumentConfig配置的方式肯定不是正確的方式,那麼如何解決呢?

可以加入一個ZuulFilter來進行統一新增下游服務context-path,首先還原上面修改的DocumentConfig,接下來新建一個Filter繼承ZuulFilter,建立一個轉發前的攔截器,將轉發地址進行修改,也就是我們需要的加入context-pa路徑,由於本文下游context-path路徑為服務名,所以案例比較簡單,內容如下:

@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;
    }
}
複製程式碼

需要注意一點,這個攔截器需要在預設ZuulFilter後執行,才能獲取requestURI和server。

再次啟動專案,就可以正常使用和訪問swagger了。

3.原始碼地址

Zuul地址:gitee.com/dalaoyang/s…

Test-service地址:gitee.com/dalaoyang/s…