目录
什么是跨域
跨域:根据浏览器的同源策略,浏览器会判断请求的URL(协议 + ip或域名 + 端口号)与目标URL的来源是否相同,如果不同,就会造成跨域问题。
造成跨越的三种情况:
- 域名不同
- 域名相同,端口号不同
- 二级域名不同
解决跨域的方式
1. Spring Boot 解决跨域
创建配置类 CorsFilter
@Configuration
public class CrossDomainConfig {
/**
* 配置Spring提供的跨域过滤器
*/
@Bean
public CorsFilter corsFilter() {
/* 跨域配置 */
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin(CorsConfiguration.ALL);// 设置访问源地址
configuration.addAllowedHeader(CorsConfiguration.ALL);// 设置访问源请求头
configuration.addAllowedMethod(CorsConfiguration.ALL);// 设置访问源请求方法
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 为所有请求添加跨域配置
source.registerCorsConfiguration("/**", configuration);
return new CorsFilter(source);
}
}
2. Spring Cloud - Gateway 解决跨域
方案一:配置 bootstrap.xml 文件
导入依赖
<!-- spring-cloud-starter-gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- spring-cloud-starter-loadbalancer(与gateway一起使用,实现负载均衡) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- Nacos 注册与发现中心 spring-cloud-starter-alibaba-nacos-discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Nacos 配置中心 spring-cloud-starter-alibaba-nacos-config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- spring-cloud-starter-bootstrap(与配置中心一起使用) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
浏览器在进行跨域请求时可能会先发一个 OPTIONS 请求以验证是否允许跨域,所以配置 add-to-simple-url-handler-mapping: true
server:
port: 8899
spring:
application:
name: gateway-service
profiles:
active: dev
cloud:
nacos:
# discovery 和 config 的 server-addr 同时需要的话,可以同时配置一个
server-addr: localhost:8848
discovery:
namespace: gateway
config:
namespace: ${spring.cloud.nacos.discovery.namespace}
file-extension: yml
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
cors-configurations: # 跨域配置列表
'[/**]': # 匹配所有路径
allowedOrigins: "*" # 允许哪些网站的跨域请求
allowedMethods: # 允许跨域的请求方式
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 3600 # 这次跨域检测的有效期,OPTIONS 有效时长,前提:两次请求相同;如果在有效时长内,之后的OPTIONS 预检请求不会发送
方案二:创建全局过滤器
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Configuration
public class CorsFilter {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter corsFilter() {
return (exchange, chain) -> {
ServerWebExchange.Builder webExchangeBuilder = exchange.mutate();
webExchangeBuilder
.request(exchange.getRequest())
.response(exchange.getResponse());
webExchangeBuilder
.response(exchange.getResponse()
.mutate()
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS")
.header("Access-Control-Allow-Headers", "Content-Type")
.build());
return chain.filter(webExchangeBuilder.build());
};
}
}
3. Nginx解决跨域(解决Nginx到网关的跨域)
server {
listen 8000;// 监听前端的端口号
server_name localhost;
location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:8080';// 路由到网关
add_header Access-Control-Allow-Headers '*';
add_header Access-Control-Allow-Methods '*';
add_header Access-Control-Allow-Credentials 'true';
return 204;
}
if ($request_method != 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:7060' always;
add_header Access-Control-Allow-Credentials 'true';
}
proxy_pass http://localhost:59200;
}
}
注意:为了方便,Access-Control-Allow-Origin设置成了*,在开发测试的时候可以这么设置,但如果是生产环境,建议不要设置成*,最好是允许哪些域名访问就设置哪些。