SpringCloud-Gateway 解决跨域问题

什么是跨域 ?

广义: 指一个域下的文档或脚本试图去请求另一个域下的资源。
狭义: 浏览器不能执行其他网站的脚本,是由浏览器同源策略限制的一类请求场景,从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。

1.基于配置文件的跨域配置

你可以在 application.yml 或 application.properties 配置文件中设置 CORS 规则。例如:

spring:
  cloud:
    gateway:
      # 全局的跨域配置
      globalcors:
        # 解决 options请求被拦截问题
        add-to-simple-url-handler-mapping: true
        cors-configurations:
          # 拦截的请求
          '[/**]':
            # 允许跨域的请求
            allowedOrigins: "*" # spring boot2.4以前的配置
            # allowedOriginPatterns: "*" # spring boot2.4以后的配置
            # 允许请求中携带的头信息
            allowedHeaders: "*"
            # 运行跨域的请求方式
            allowedMethods: "*"
            # 是否允许携带cookie
            alloweCredentials: true
            # 跨域检测的有效期,单位s
            maxAge: 36000

2.基于 Java 配置的跨域配置

除了在配置文件中设置,你也可以在 Java 类中配置 Spring Cloud Gateway 的跨域支持。这可以通过 CorsWebFilter 来完成。

创建 CorsWebFilter Bean:

//加配置文件
@Configuration
public class CorsConfig {

//跨域检测的有效期,单位s
private static final String MAX_AGE = "18000L";

//支持跨域的域名,可放在配置文件里面
@Value("${cors.whitelist}")
private List<string> CORS WHITELIST;

@Bean
public WebFilter corsFilter() {
	return (ServerWebExchangectx,WebFilterChain chain) -> {
		ServerHttpRequest request = ctx.getRequest(); 
		if (CorsUtils.isCorsRequest(request)) {
			HttpHeaders requestHeaders = request.getHeaders(); 
			ServerHttpResponse 	response = ctx.getResponse();
			HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); 
			HttpHeaders headers = response.getHeaders(); 
			string origin = requestHeaders.getorigin();
			if (CORS_WHITELIST.contains(origin) Il CollectionUtils.isEmpty(CORS WHITELIST)) {
			headers.add(HttpHeaders.ACCESS_CONTROL ALLOW ORIGIN,origin);} 
			else {
			headers.add(HttpHeaders.ACCESS_CONTROL ALLOW ORIGIN, CORS_WHITELIST.get(0));
			}		
			headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,requestHeaders.getAccessControlRequestHeaders());
			headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS,headerValue:"true"); 				    
			headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS,headerValue:"*"); 			
			headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE,MAX AGE); 
			if (request.getMethod() == HttpMethod.OPTIONS){
				response.setstatusCode(HttpStatus.OK); 
				return Mono.empty();
			}
		}				
		return chain.filter (ctx);
	};
}

3.基于 Route 配置跨域(限特定路由)

你还可以基于路由配置 CORS 规则,这样只对特定的路由应用跨域设置。你可以在 Spring Cloud Gateway 的路由配置中使用 cors() 方法来实现。

import org.springframework.cloud.gateway.config.GlobalCorsProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(r -> r.path("/api/**")
                        .filters(f -> f.cors(cors -> cors.allowedOrigins("*"))
                                .addRequestHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
                                .addRequestHeader("Access-Control-Allow-Headers", "Authorization, Content-Type"))
                        .uri("http://localhost:8081"))
                .build();
    }
}

在这个例子中:

  • 通过 cors() 方法为 /api/** 路由路径配置了跨域规则。
  • 使用 addRequestHeader 添加了 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers 请求头,以支持跨域请求。

4.解决预检请求(OPTIONS)

跨域请求有时会触发预检请求(OPTIONS 请求),它是浏览器自动发起的一种请求,检查实际请求是否安全可接受。如果你的网关处理预检请求不当,可能会出现跨域问题。

你可以通过添加 OPTIONS 请求的处理来解决这个问题。确保你的网关可以处理预检请求:

spring:
  cloud:
    gateway:
      routes:
        - id: api_route
          uri: http://localhost:8081
          predicates:
            - Path=/api/**
          filters:
            - name: AddRequestHeader
              args:
                name: Access-Control-Allow-Origin
                value: "*"
            - name: AddRequestHeader
              args:
                name: Access-Control-Allow-Methods
                value: "GET, POST, PUT, DELETE, OPTIONS"
            - name: AddRequestHeader
              args:
                name: Access-Control-Allow-Headers
                value: "Authorization, Content-Type"
            - name: AddRequestHeader
              args:
                name: Access-Control-Allow-Credentials
                value: "true"

或者,你也可以通过在 Spring Cloud Gateway 中直接添加预检请求的过滤器来自动处理 OPTIONS 请求。

5.配置 CORS 和 Spring Security 兼容

如果你的 Spring Cloud Gateway 后端服务启用了 Spring Security,也可能会遇到跨域请求的问题,尤其是在涉及认证(如 JWT)时。为了确保 CORS 配置与 Spring Security 配置不冲突,你需要在 Spring Security 配置中显式启用 CORS 支持。

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()  // 启用 CORS
            .authorizeRequests()
                .antMatchers("/api/**").permitAll()
                .anyRequest().authenticated();
    }
}

在这里,http.cors().and() 启用了 CORS 支持,并允许跨域请求。