When SpringCloud Gateway integrates the interface of a service after Springfox(SwaggerUI3), the request path will not add the corresponding service name problem.

Posted by kaos057 on Wed, 09 Mar 2022 15:05:37 +0100

Write in front

When you see this article, it has been integrated by default Springcloud/gateway/springfox(swaggerui3), It's just a problem when testing the service.

Problem description

When accessing through the swagger UI page, we will ignore the service name and directly access the interface mapped by swagger, but we forward it through the gateway, so the access will be directly 404; As follows:

The problem is that the servers mapping does not meet our requirements. What I need is servers with the service name, but by default, only the ip and port of the gateway, without the current service name; As shown in the figure below:

It's strange that I tried to change the Inferred Url by adding servers to the swagger configuration, but it was always invalid. After debug ging, I found that there were no servers after the execution of line 96 in the AbstractDocumentationPluginsBootstrapper class, resulting in no servers at the time of request. Then swagger will create a default servers, which is the ip + port of the gateway.

Now the problem has been found. Either modify the scan method or do something when building the default embedded URL when requesting. After looking at the code, it is found that it is easier to change the default embedded URL when requesting, so the creation method is modified; The default invocation and creation methods are as follows:

Solution

In this way, you can create a package with the same complete package path, create a class with the same name to cover the class in the framework, and then add the service name when creating the embedded URL. The service name Swagger has been put in the request header, and you can take it out and add it.
SpecGeneration.java

package springfox.documentation.oas.web;

import io.swagger.v3.oas.models.servers.Server;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * Try to replace the class in the framework with this class
 *
 * @author vains
 * @date 2021/4/6 11:21
 */
@Slf4j
public class SpecGeneration {

    private static final String HEADER_NAME = "X-Forwarded-Prefix";
    private static final Logger LOGGER = getLogger(SpecGeneration.class);
    public static final String OPEN_API_SPECIFICATION_PATH
            = "${springfox.documentation.open-api.v3.path:/v3/api-docs}";
    protected static final String HAL_MEDIA_TYPE = "application/hal+json";

    private SpecGeneration() {
        throw new UnsupportedOperationException();
    }

    /**
     * Create a default swagger server
     *
     * @param requestPrefix /v3/api-docs
     * @param requestUrl    Requested url
     * @return Server
     */
    public static Server inferredServer(String requestPrefix, String requestUrl) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String serverUrl = requestUrl.replace(requestPrefix, "");
        String header = null;
        try {
            URI url = new URI(requestUrl);
            serverUrl = String.format("%s://%s:%s", url.getScheme(), url.getHost(), url.getPort());
            header = request.getHeader(HEADER_NAME);
            if (!StringUtils.isEmpty(header)) {
                log.info("The current services are:{}", header);
                serverUrl += header;
            }
        } catch (URISyntaxException e) {
            LOGGER.error("Unable to parse request url:" + requestUrl);
        }
        String description = "Inferred Url";
        if (!StringUtils.isEmpty(header)) {
            description += " For " + header.substring(1);
        }
        return new Server()
                .url(serverUrl)
                .description(description);
    }

    public static String decode(String requestURI) {
        try {
            return URLDecoder.decode(requestURI, StandardCharsets.UTF_8.toString());
        } catch (UnsupportedEncodingException e) {
            return requestURI;
        }
    }
}

Note that the path of the package must not be wrong!! Then, this class only needs to ensure that the project configured with swagger can be accessed

effect

Then open the / swagger UI / page and you will find that the service name has been added successfully.

An interface is also requested, and the path is correct.

So far, the problem has been solved.
If you have any questions or better solutions, you can leave a message in the comment area. Thank you.

Topics: Java Spring Cloud gateway