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

如何让Zuul代理处理跨域?配置后仍报403问题排查

解决Zuul网关下跨域403问题的正确姿势

你遇到的问题很典型:把跨域配置从微服务移到Zuul后没生效,核心原因有两个:Zuul默认的Spring MVC跨域配置没生效,以及微服务依然在校验外部请求的Origin头。下面一步步帮你解决:

1. 先让Zuul真正处理跨域请求

你之前用WebMvcConfigurerAdapter配置跨域,对Zuul来说可能不生效——因为Zuul的请求流转是通过ZuulFilter,而非Spring MVC的DispatcherServlet。正确的做法是用CorsFilter来配置Zuul的跨域:

@Configuration
public class ZuulCorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        
        // 允许前端携带Cookie等凭证(如果需要的话)
        config.setAllowCredentials(true);
        // 生产环境建议替换成你的前端域名,比如"https://your-frontend.com"
        config.setAllowedOrigins(Collections.singletonList("*"));
        // 允许的请求头,覆盖常见场景
        config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept", "Authorization", "X-Requested-With"));
        // 允许的HTTP方法
        config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        // 暴露给前端的响应头(比如自定义的token头)
        config.setExposedHeaders(Arrays.asList("Authorization"));
        
        source.registerCorsConfiguration("/api/**", config); // 对应你的Zuul前缀/api
        return new CorsFilter(source);
    }
}

这个过滤器会在Zuul层面直接处理跨域预检请求(OPTIONS),并给响应添加正确的CORS头,避免请求到达微服务时触发跨域校验。

2. 让微服务识别并信任来自Zuul的请求

现在Zuul已经处理了跨域,但微服务收到的请求里依然带有前端的Origin头,它会认为这是外部直接请求,所以返回403。我们需要给Zuul转发的请求加一个“内部标识”,让微服务信任这些请求:

第一步:给Zuul添加请求头过滤器

创建一个Zuul前置过滤器,给转发的请求添加自定义头:

@Component
public class InternalRequestMarkerFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return "pre"; // 在请求转发前执行
    }

    @Override
    public int filterOrder() {
        return 1; // 优先级尽量高,确保头被添加
    }

    @Override
    public boolean shouldFilter() {
        return true; // 对所有请求生效
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        // 添加自定义头,标识这是Zuul转发的内部请求
        ctx.addZuulRequestHeader("X-Internal-Proxy", "Zuul");
        return null;
    }
}

第二步:微服务端校验内部标识

修改微服务的CORS配置,只对没有这个自定义头的请求做跨域限制(或者直接拒绝外部直接请求):

方案A:通过过滤器拒绝外部直接调用

如果不允许微服务被直接访问,直接加一个过滤器拦截无标识的请求:

@Configuration
public class MicroserviceSecurityConfig {

    @Bean
    public FilterRegistrationBean<Filter> internalRequestValidationFilter() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new Filter() {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                HttpServletRequest req = (HttpServletRequest) request;
                String internalProxyHeader = req.getHeader("X-Internal-Proxy");
                
                // 如果没有自定义头,直接返回403
                if (internalProxyHeader == null || !"Zuul".equals(internalProxyHeader)) {
                    HttpServletResponse res = (HttpServletResponse) response;
                    res.sendError(HttpServletResponse.SC_FORBIDDEN, "Direct access to microservice is not allowed");
                    return;
                }
                chain.doFilter(request, response);
            }
        });
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }

    // 如果你还是需要允许特定场景的直接调用,可以保留基础CORS配置,否则可以移除之前的CorsConfig
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 只允许内部测试域名或者Zuul的内部地址
        registry.addMapping("/**")
                .allowedOrigins("http://zuul-internal:8080")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS");
    }
}

方案B:修改CORS配置信任Zuul

如果需要允许微服务被内部其他服务调用,可以修改CORS配置,允许Zuul的内部地址:

@Configuration
public class MicroserviceCorsConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                // 替换成你的Zuul内部访问地址(比如容器内域名或IP)
                .allowedOrigins("http://my-zuul-gateway:8080")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true);
    }
}

3. 额外注意事项

  • 生产环境不要用*作为AllowedOrigins:一定要指定具体的前端域名,避免安全风险。
  • Spring Security兼容性:如果微服务用了Spring Security,需要确保它允许OPTIONS请求,并且不拦截CORS相关的头。可以在Security配置里添加:
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS).permitAll()
            // 其他配置...
    }
    
  • Zuul前缀配置:确保你的Zuul前缀/api和CORS配置的路径匹配,避免遗漏。

这样配置后,前端的跨域请求会由Zuul处理,微服务只会接受来自Zuul的请求,外部直接调用微服务会被拒绝,完全符合你的设计预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:20:28