暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Zuul整合Swagger,使用ZuulFilter解决下游服务context-path

dalaoyang 2019-12-09
355

问题起因:使用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服务,配置如下:

  1. zuul.routes.test-service.path=/test-service/**

  2. zuul.routes.test-service.service-id=test-service

复制

配置swagger配置文件,如下:

  1. @Configuration

  2. @EnableSwagger2

  3. public class SwaggerConfig {


  4. @Bean

  5. public Docket createRestApi() {

  6. return new Docket(DocumentationType.SWAGGER_2)

  7. .apiInfo(apiInfo());

  8. }


  9. private ApiInfo apiInfo() {

  10. return new ApiInfoBuilder()

  11. .title("使用Swagger2构建RESTful APIs")

  12. .description("关注博主博客:https://www.dalaoyang.cn/")

  13. .termsOfServiceUrl("https://www.dalaoyang.cn/")

  14. .contact("dalaoyang")

  15. .version("1.0")

  16. .build();

  17. }

  18. }

复制

新建文档配置,这里主要目的是为了聚合下游服务的swagger,内容很好理解,就是讲SwaggerResource赋值,其中name为swagger的api文档名,location为对应api-docs地址,version为版本,这里利用ZuulProperties来生成对应文档,避免写死代码,完整内容如下:

  1. @Primary

  2. @Component

  3. public class DocumentConfig implements SwaggerResourcesProvider {


  4. @Autowired

  5. private ZuulProperties zuulProperties;


  6. @Override

  7. public List<SwaggerResource> get() {

  8. List<SwaggerResource> swaggerResources = new ArrayList<>();

  9. Map<String, ZuulProperties.ZuulRoute> routes = zuulProperties.getRoutes();

  10. for (String serviceName : routes.keySet()) {

  11. SwaggerResource swaggerResource = initSwaggerResource(serviceName,

  12. "/" + serviceName + "/v2/api-docs", "1.0.0");

  13. swaggerResources.add(swaggerResource);

  14. }

  15. return swaggerResources;

  16. }


  17. private SwaggerResource initSwaggerResource(String name, String location, String version) {

  18. SwaggerResource swaggerResource = new SwaggerResource();

  19. swaggerResource.setName(name);

  20. swaggerResource.setLocation(location);

  21. swaggerResource.setSwaggerVersion(version);

  22. return swaggerResource;

  23. }

  24. }

复制

配置到这里,其实已经完成了,访问网关swagger如图所示:

2.下游服务存在context-path怎么办?

从上面其实可以了解到,聚合文档的操作,其实就是将下游服务的/v2/api-docs整合进来,当然,可以在本文DocumentConfig中将下游服务context-path加入其中,注意注释阶段,完整代码如下:

  1. @Primary

  2. @Component

  3. public class DocumentConfig implements SwaggerResourcesProvider {


  4. @Autowired

  5. private ZuulProperties zuulProperties;


  6. @Override

  7. public List<SwaggerResource> get() {

  8. List<SwaggerResource> swaggerResources = new ArrayList<>();

  9. Map<String, ZuulProperties.ZuulRoute> routes = zuulProperties.getRoutes();

  10. for (String serviceName : routes.keySet()) {

  11. //假设下游服务的context-path为服务名

  12. SwaggerResource swaggerResource = initSwaggerResource(serviceName,

  13. "/" + serviceName +"/" + serviceName + "/v2/api-docs", "1.0.0");

  14. swaggerResources.add(swaggerResource);

  15. }

  16. return swaggerResources;

  17. }


  18. private SwaggerResource initSwaggerResource(String name, String location, String version) {

  19. SwaggerResource swaggerResource = new SwaggerResource();

  20. swaggerResource.setName(name);

  21. swaggerResource.setLocation(location);

  22. swaggerResource.setSwaggerVersion(version);

  23. return swaggerResource;

  24. }

  25. }

复制

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

  1. server.servlet.context-path=/test-service

复制

启动服务,访问Zuul的swagger文档,还是可以同样的访问,但是测试一下在swagger请求一下下游服务api,如下

很明显,404的原因就是因为转发下游服务的时候,没有加上context-path,在本文DocumentConfig配置的方式肯定不是正确的方式,那么如何解决呢?

可以加入一个ZuulFilter来进行统一添加下游服务context-path,首先还原上面修改的DocumentConfig,接下来新建一个Filter继承ZuulFilter,创建一个转发前的拦截器,将转发地址进行修改,也就是我们需要的加入context-pa路径,由于本文下游context-path路径为服务名,所以案例比较简单,内容如下:

  1. @Component

  2. public class UrlPathFilter extends ZuulFilter {


  3. @Override

  4. public String filterType() {

  5. return FilterConstants.PRE_TYPE;

  6. }


  7. @Override

  8. public int filterOrder() {

  9. return 6;

  10. }


  11. @Override

  12. public boolean shouldFilter() {

  13. return true;

  14. }


  15. @Override

  16. public Object run() throws ZuulException {

  17. RequestContext requestContext = RequestContext.getCurrentContext();

  18. Object requestURI = requestContext.get(FilterConstants.REQUEST_URI_KEY);

  19. Object server = requestContext.get(FilterConstants.PROXY_KEY);

  20. String finalURI = "/" + server + requestURI;

  21. requestContext.put(FilterConstants.REQUEST_URI_KEY, finalURI);

  22. return null;

  23. }

  24. }

复制

需要注意一点,这个拦截器需要在默认ZuulFilter后执行,才能获取requestURI和server。

再次启动项目,就可以正常使用和访问swagger了。

3.源码地址

Zuul地址:https://gitee.com/dalaoyang/springcloudlearn/tree/master/springcloudswagger_zuul

Test-service地址:https://gitee.com/dalaoyang/springcloudlearn/tree/master/springcloudswagger_service


-END-


文章转载自dalaoyang,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论