跨域问题的解决和跨域的原理
什么情况下会发送跨域请求?
最常见场景:前后端分类项目会发送跨域
- 前端将baseUrl写好并不能解决跨域问题
- 不同的协议:请求从
http
页面到https
页面,或者从https
页面到http
页面。 - 不同的域名:例如从
example.com
请求api.example.org
。 - 不同的端口:同一域名下的不同端口,例如从
example.com:80
请求example.com:8080
。
浏览器的同源策略,限制了不同源之间的资源访问。
- 不同源:
- 不同协议
- 不同域名
- 不同端口
- 原理
- 预检请求 (Preflight Request): 对于某些跨域请求(尤其是复杂请求),浏览器会先发起一个
OPTIONS
请求来检查服务器是否允许实际请求。这称为预检请求。
Access-Control-Allow-Origin
: 这是最核心的CORS头部,它告诉浏览器哪些来源的请求被允许。比如,Access-Control-Allow-Origin: https://example.com
允许https://example.com
访问资源。Access-Control-Allow-Methods
: 指定允许的HTTP方法,比如GET, POST, PUT
。Access-Control-Allow-Headers
: 指定允许的请求头部字段。Access-Control-Allow-Credentials
: 指定是否允许发送凭据(如Cookies或HTTP认证信息)。- 在不允许跨域时,进行跨域请求,会发生什么?是否报错?能否请求到资源
- 浏览器阻止请求:当你尝试从一个源(例如
https://example.com
)请求另一个源(例如https://api.example.org
)的资源时,如果目标服务器没有正确配置CORS头部,浏览器会阻止这次请求。- 控制台报错:浏览器的开发者工具控制台会显示错误信息,通常是关于CORS的错误。这些错误信息会指出请求被阻止的原因,例如:“CORS policy: No ‘Access-Control-Allow-Origin’ header” 或 “CORS policy: The ‘Access-Control-Allow-Origin’ header has a value ‘*’ that is not allowed” 等。
跨域请求
- XMLHttpRequest(XHR): 用于通过JavaScript从客户端发起异步请求。
- AJAX: 异步JavaScript和XML,用于动态加载数据。
- restCilent: java中请求第三方接口
何如去解决跨域问题?
仅仅列举最常见解决方式
通过注解跨域
@RestController
@CrossOrigin(origins = "*")
配置类实现
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")//允许跨域的域名
.allowedMethods("*")//允许任何方法
.allowCredentials(false)//带上cookie信息
.maxAge(3600) //maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
.allowedHeaders("*");
}
}
通过crossFilter跨域
实现方式和上面基本一样
@Configuration // 一定不能忽略此注解
public class MyCorsFilter {
@Bean
public CorsFilter corsFilter() {
// 1.创建 CORS 配置对象
CorsConfiguration config = new CorsConfiguration();
// 支持域
config.addAllowedOriginPattern("*");
// 是否发送 Cookie
config.setAllowCredentials(true);
// 支持请求方式
config.addAllowedMethod("*");
// 允许的原始请求头部信息
config.addAllowedHeader("*");
// 暴露的头部信息
config.addExposedHeader("*");
// 2.添加地址映射
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**", config);
// 3.返回 CorsFilter 对象
return new CorsFilter(corsConfigurationSource);
}
}
通过Response跨域
@RestController
public class TestController {
@RequestMapping("/test")
public HashMap<String, Object> test(HttpServletResponse response) {
// 设置跨域,上面原理中有解决
response.setHeader("Access-Control-Allow-Origin", "*");
return new HashMap<String, Object>() {{
put("state", 200);
put("data", "success");
put("msg", "");
}};
}