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等進行注釋

這里不做代碼介紹,具體可以查看我的另一篇文章:https://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", "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;
    }
}

下游服務加入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地址:https://gitee.com/dalaoyang/springcloud_learn/tree/master/springcloud_swagger_zuul

Test-service地址:https://gitee.com/dalaoyang/springcloud_learn/tree/master/springcloud_swagger_service


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM