Spring Cloud Gateway对接React与NodeJS的CORS预检问题求助
Spring Cloud Gateway 跨域(CORS)问题解决
问题描述
在React应用(运行在http://localhost:3000)和NodeJS服务之间搭建Spring Cloud Gateway时,React端触发CORS错误:
Access to XMLHttpRequest at 'http://localhost:8080/graphql' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
已尝试的无效方案
方案1:全局CORS配置
添加以下配置后问题未解决;补充allowedHeaders后,出现多Origin冲突错误:
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedOrigins=* spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedMethods=*
错误信息:
The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:3000, *', but only one is allowed.
方案2:自定义CORS过滤器Bean
编写以下过滤器Bean后,问题仍存在:
@Bean Function<GatewayFilterSpec, UriSpec> brutalCorsFilters() { return f -> f .setResponseHeader("Access-Control-Allow-Origin", "*") .setResponseHeader("Access-Control-Allow-Methods", "*") .setResponseHeader("Access-Control-Expose-Headers", "*"); }
正确解决方法
方法1:完善全局CORS配置(推荐)
在application.yml或application.properties中配置全局CORS,同时确保网关处理预检请求,且后端服务不要重复设置CORS头:
spring: cloud: gateway: globalcors: cors-configurations: '[/**]': allowedOrigins: "http://localhost:3000" # 明确指定前端域名,带Cookie时不能用* allowedMethods: "*" allowedHeaders: "*" allowCredentials: true # 前端带Cookie时必须开启 exposedHeaders: "*" add-to-simple-url-handler-mapping: true # 让网关接管OPTIONS预检请求
如果不需要带Cookie,可将allowedOrigins设为*,但仍需确保后端无重复CORS头设置。
方法2:自定义优先级CORS过滤器
若全局配置不生效,可能是过滤器顺序问题,可编写优先级更高的过滤器专门处理CORS:
import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; @Component public class CorsFilter extends AbstractGatewayFilterFactory<CorsFilter.Config> { public CorsFilter() { super(Config.class); } @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { // 直接处理OPTIONS预检请求,不转发到后端 if (exchange.getRequest().getMethod() == HttpMethod.OPTIONS) { exchange.getResponse().setStatusCode(HttpStatus.OK); exchange.getResponse().getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "http://localhost:3000"); exchange.getResponse().getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "*"); exchange.getResponse().getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*"); exchange.getResponse().getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); return exchange.getResponse().setComplete(); } // 给正常响应添加CORS头 exchange.getResponse().getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "http://localhost:3000"); exchange.getResponse().getHeaders().add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); return chain.filter(exchange); }; } public static class Config { // 可根据需求添加自定义配置参数 } }
之后在路由配置中引用该过滤器,或设置为全局过滤器即可。
核心注意事项
- 禁止重复设置CORS头:后端NodeJS服务不能再设置
Access-Control-Allow-Origin等CORS相关头,否则会和网关的头冲突,触发多值错误。 - 预检请求必须由网关处理:OPTIONS请求不能转发到后端,否则后端可能无法正确响应预检要求。
- 带Cookie的特殊限制:如果前端请求需要携带Cookie,
allowedOrigins必须明确指定域名,不能使用*,同时开启allowCredentials: true。
内容的提问来源于stack exchange,提问作者Smit
相关产品推荐
相关产品推荐

