You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Swagger中适配Zuul路由与过滤器,修正文档路径偏差问题?

解决Zuul路由导致Swagger文档base-path不匹配的问题

当然可以通过Zuul过滤器来修正这个问题,让Swagger文档的base-path和实际路由完全一致,我之前帮不少开发者处理过类似场景,下面给你两种可行的方案:

一、手动编写Zuul Pre过滤器修正Swagger文档

我们可以编写一个Zuul的PreFilter,在请求到达Swagger文档接口时,动态修改返回的Swagger JSON中的basePath字段,让它和Zuul实际路由后的路径匹配。

过滤器代码示例

@Component
public class SwaggerBasePathFilter extends ZuulFilter {

    private static final String SWAGGER_DOC_PATH = "/v2/api-docs";
    private static final String X_FORWARDED_PREFIX = "X-Forwarded-Prefix";

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        // 只处理Swagger文档请求
        return SWAGGER_DOC_PATH.equals(request.getRequestURI());
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        
        // 获取Zuul路由后的实际前缀(可以从请求头或Zuul的路由信息中获取)
        String actualBasePath = request.getHeader(X_FORWARDED_PREFIX);
        if (actualBasePath == null) {
            // 如果没有转发头,也可以从Zuul的路由匹配结果中获取
            Route route = ctx.getRoute();
            if (route != null) {
                actualBasePath = route.getPrefix();
            }
        }

        if (actualBasePath != null) {
            // 拦截响应,修改Swagger的basePath
            ctx.addZuulResponseHeader("Content-Type", "application/json");
            ctx.setResponseBodyFilteringEnabled(true);
            ctx.getResponse().setCharacterEncoding("UTF-8");
            
            // 通过ResponseBodyWrapper来修改返回的JSON内容
            ctx.setResponseWrapper(new SwaggerBasePathResponseWrapper(ctx.getResponse(), actualBasePath));
        }

        return null;
    }

    // 自定义响应包装类,修改Swagger JSON的basePath
    private static class SwaggerBasePathResponseWrapper extends HttpServletResponseWrapper {
        private final String actualBasePath;
        private ByteArrayOutputStream byteArrayOutputStream;
        private PrintWriter printWriter;

        public SwaggerBasePathResponseWrapper(HttpServletResponse response, String actualBasePath) {
            super(response);
            this.actualBasePath = actualBasePath;
            this.byteArrayOutputStream = new ByteArrayOutputStream();
            this.printWriter = new PrintWriter(byteArrayOutputStream);
        }

        @Override
        public PrintWriter getWriter() throws IOException {
            return printWriter;
        }

        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return new ServletOutputStream() {
                @Override
                public void write(int b) throws IOException {
                    byteArrayOutputStream.write(b);
                }

                @Override
                public boolean isReady() {
                    return true;
                }

                @Override
                public void setWriteListener(WriteListener writeListener) {}
            };
        }

        @Override
        public void flushBuffer() throws IOException {
            printWriter.flush();
            // 读取原始响应内容,替换basePath
            String swaggerJson = byteArrayOutputStream.toString("UTF-8");
            swaggerJson = swaggerJson.replace("\"basePath\":\"/api\"", "\"basePath\":\"" + actualBasePath + "\"");
            // 写入修改后的内容到响应
            getResponse().getOutputStream().write(swaggerJson.getBytes("UTF-8"));
            byteArrayOutputStream.reset();
        }
    }
}

代码说明

  • 这个过滤器只会拦截Swagger的文档请求(/v2/api-docs),避免影响其他接口。
  • 通过X-Forwarded-Prefix请求头或者Zuul的路由信息获取实际的路由前缀,然后动态替换Swagger JSON中的basePath字段。
  • 自定义的HttpServletResponseWrapper用来修改响应内容,确保返回的Swagger文档使用正确的base-path。

二、调整Swagger Docket配置配合过滤器

结合你当前的Docket配置,我们可以让Swagger动态获取Zuul的路由前缀,而不是固定写死/api:

@Bean
public Docket swaggerSpringfoxDocket(HttpServletRequest request) {
    this.log.debug("Starting Swagger");
    StopWatch watch = new StopWatch();
    watch.start();
    
    // 从请求头或Zuul上下文获取实际basePath
    String basePath = request.getHeader("X-Forwarded-Prefix");
    if (basePath == null) {
        basePath = "/api"; // 默认值
    }

    Docket docket = new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            .forCodeGeneration(false)
            .select()
            .paths(regex(basePath + "/.*")) // 动态匹配路径
            .build()
            .pathMapping(basePath); // 设置正确的basePath

    watch.stop();
    this.log.debug("Started Swagger in {} ms", watch.getTotalTimeMillis());
    return docket;
}

说明

  • 这里通过HttpServletRequest获取Zuul转发的前缀,动态设置Docket的pathMapping和路径匹配规则,让Swagger生成的文档一开始就使用正确的base-path。
  • 配合上面的Zuul过滤器,可以双重保障Swagger文档的路径准确性。

额外提示

  • 如果你的Zuul是动态增减路由的,建议开启Zuul的路由刷新功能,确保过滤器能实时获取最新的路由信息。
  • 测试的时候可以直接访问Swagger UI,检查每个接口的请求路径是否和实际路由一致,比如点击“Try it out”按钮,看请求的URL是否正确。

内容的提问来源于stack exchange,提问作者riddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:02:10