在编写 SpringBoot 前后端分离项目时, 出现了一个问题: 前端无法得到后端响应的数据, 浏览器对请求进行了拦截
原因: 前端调用的后端接口和前端不属于同一个域, 就会产生跨域问题, 也就是说你的应用访问了该应用域名或端口之外的域名或端口
要同时满足三个条件才会产生跨域问题,这也就是为什么会产生跨域的原因。
- 浏览器限制,而不是服务端限制
- 请求地址的域名或端口和当前访问的域名或端口不一样
- 发送的是 XHR(XMLHttpRequest)请求,可以使用 a 标签(模拟xhr请求)和 img 标签(模拟json请求)做对比(控制台只报了一个跨域异常)
解决思路:
- 浏览器解除跨域问题 (可以但不合理)
- 用 JSONP 代替 XHR 请求 (不好用)
- CORS 方案 (好用)
CORS 跨域共享
跨源资源共享(Cross-origin resource sharing, CORS)是由大多数浏览器实现的 W3C 规范,它允许您以灵活的方式指定哪种跨域请求被授权,而不是使用一些不太安全、功能不太强大的方法,比如 IFRAME 或 JSONP
方案具体原理这里不赘述
在 Spring Boot 中使用带有 @CrossOrigin 注释的 Controller 方法 CORS 配置,不需要任何特定的配置 (如果仍然有跨域问题, 1. 请检查访问地址是否出现错误 2. 请求方法(一级映射和二级均需要 如/user/login 中的 user 和 login)需要指定请求方式 Post / Get)
//实现跨域注解
//origin="*" 代表所有域名都可访问, 可以省略
//maxAge 响应的缓存持续时间的最大年龄,简单来说就是 Cookie 的有效期 单位为秒
//若 maxAge 是负数,则代表为临时 Cookie,不会被持久化, Cookie 信息保存在浏览器内存中,浏览器关闭 Cookie 就消失
源码:
@Target({
ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
String[] DEFAULT_ORIGINS = {
"*" };
String[] DEFAULT_ALLOWED_HEADERS = {
"*" };
boolean DEFAULT_ALLOW_CREDENTIALS = true;
long DEFAULT_MAX_AGE = 1800;
/**
* 同origins属性一样
*/
@AliasFor("origins")
String[] value() default {
};
/**
* 所有支持域的集合,例如"http://domain1.com"。
* <p>这些值都显示在请求头中的Access-Control-Allow-Origin
* "*"代表所有域的请求都支持
* <p>如果没有定义,所有请求的域都支持
* @see #value
*/
@AliasFor("value")
String[] origins() default {
};
/**
* 允许请求头重的header,默认都支持
*/
String[] allowedHeaders() default {
};
/**
* 响应头中允许访问的header,默认为空
*/
String[] exposedHeaders() default {
};
/**
* 请求支持的方法,例如"{RequestMethod.GET, RequestMethod.POST}"}。
* 默认支持RequestMapping中设置的方法
*/
RequestMethod[] methods() default {
};
/**
* 是否允许cookie随请求发送,使用时必须指定具体的域
*/
String allowCredentials() default "";
/**
* 预请求的结果的有效期,默认30分钟
*/
long maxAge() default -1;
}