Cause: Zuul gateway service needs to integrate the swagger of the downstream system, but the downstream service has context-path configuration and cannot redirect correctly. ZuulFilter is used to solve the problem.

1.Zuul integrates downstream Swagger

First of all, how Zuul integrates downstream service Swagger is introduced. It is easy to understand that swagger of downstream service can be put into the same page through Zuul swagger address. The flow diagram is as follows:

1.1 Downstream services integrate Swagger

There are two steps to swagger:

  1. Configuration swagger
  2. Annotate apis, models, etc

Here don’t do code is introduced, specific can check my another article: www.dalaoyang.cn/article/21, or view the source code in this paper.

There is only one new service named test-service.

1.2 Zuul aggregates downstream Swagger

Zuul configuration is not described here. Configure the downstream service route, that is, access the test-service/** and forward the route to the test-service.

zuul.routes.test-service.path=/test-service/**
zuul.routes.test-service.service-id=test-service
Copy the code

Configure the Swagger profile as follows:

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Build RESTful APIs with Swagger2")
                .description("Focus on blogger blog: https://www.dalaoyang.cn/")
                .termsOfServiceUrl("https://www.dalaoyang.cn/")
                .contact("dalaoyang")
                .version("1.0") .build(); }}Copy the code

Where name is the API file name of Swagger, location is the corresponding API-docs address, version is the version. To avoid dead code, use ZuulProperties to generate the corresponding document. The complete content is as follows:

@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);
        returnswaggerResource; }}Copy the code

Configuration to here is actually done, access gateway Swagger as shown in the figure:

2. What if the downstream service has context-Path?

As can be seen from the above, the operation of aggregating documents is actually to integrate /v2/ apI-docs of the downstream service. Of course, the downstream service context-path can be added into DocumentConfig in this paper. Note the annotation stage, and the complete code is as follows:

@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 : SwaggerResource = initSwaggerResource(serviceName, routes.keyset ()) {// assume that context-path is the serviceName of the service."/" + 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);
        returnswaggerResource; }}Copy the code

Add the downstream service to the context-path configuration as follows:

server.servlet.context-path=/test-service
Copy the code

Start the service and access Zuul’s Swagger document. The same access is still available, but test the downstream service API in swagger request as follows

It is obvious that the reason for 404 is that context-path is not added when forwarding downstream services. The DocumentConfig configuration in this paper is definitely not the correct one. So how to solve this problem?

You can add a ZuulFilter to uniformly add the downstream service context-Path. First restore the DocumentConfig modified above, then create a new Filter to inherit ZuulFilter, create an interceptor before forwarding, and modify the forwarding address. That is, we need to add the context-pa path. Since the downstream context-path of this article is the service name, the case is relatively simple, and the content is as follows:

@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);
        returnnull; }}Copy the code

Note that the interceptor needs to be executed after the default ZuulFilter to get the requestURI and server.

Start the project again and you can use and access Swagger normally.

3. Source code address

Zuul address: gitee.com/dalaoyang/s…

Test-service address: gitee.com/dalaoyang/s…