之前遇到问题的时候在语雀撸的笔记,整一份到博客,方便浏览。
前言:问题来自在进行前后端分离的过程中,前端部分单独运行自己的服务,后端部分单独运行自己的服务,但二者之间却无法进行数据接口的连接,问题就是在于资源跨域问题,下面来了解一下这个资源跨域及其解决办法。
在跨源之前先了解一下源和同源是什么?
一、同源策略
同源策略,我觉得wiki解释得不错:
同源策略是指在Web浏览器中,允许某个网页脚本访问另一个网页的数据,但前提是这两个网页必须有相同的URI、主机名和端口号,一旦两个网站满足上述条件,这两个网站就被认定为具有相同来源。此策略可防止某个网页上的恶意脚本通过该页面的文档对象模型访问另一网页上的敏感数据。
同源策略对Web应用程序具有特殊意义,因为Web应用程序广泛依赖于HTTP cookie[1]来维持用户会话,所以必须将不相关网站严格分隔,以防止丢失数据泄露。
值得注意的是同源策略仅适用于脚本,这意味着某网站可以通过相应的HTML标签[2]访问不同来源网站上的图像、CSS和动态加载脚本等资源。
下面再来看个例子,判断下列哪些URL与URL**http://www.example.com/dir/page.html** 属于相同来源:
URL | 结果 | 原因 |
---|---|---|
http://www.example.com/dir/page2.html | 是 | 只有路径不同 |
http://www.example.com/dir2/other.html | 是 | 只有路径不同 |
**http://**username:password@www.example.com/dir2/other.html | 是 | 只有路径不同 |
http://www.example.com:81/dir/other.html | 否 | 不同端口(若未标明,http:// 默认端口号为80) |
https://www.example.com/dir/other.html | 否 | 不同协议(https和http) |
http://en.example.com/dir/other.html | 否 | 不同域名 |
http://example.com/dir/other.html | 否 | 不同域名(需要完全匹配) |
http://v2.www.example.com/dir/other.html | 否 | 不同域名(需要完全匹配) |
总的来说就是无论是几个网站,只要有相同的URI、主机名和端口号它们就是同源,禁止非同源的脚本相互访问是浏览器的安全措施。因此解决跨域问题即解决URI、主机名和端口的问题。
了解了同源,我们再来了解一下跨源问题。
二、跨源
跨源问题可以基于同源进行探讨,同源要求URI、主机名和端口号相同,那么跨源即是一个页面访问多个不同的URI、主机名和端口号的资源的问题,即跨源资源共享CORS。详情可看WIKI。
同源策略是一个安全策略,它是具有两面性的,它能屏蔽恶意请求,但当我们需要进行跨域操作的时候就无法进行,比如前后端分离的时候。因此,当我们有需求的时候,我们可以进行跨源资源共享操作。
没有同源策略的带来的影响,可以看一眼:对于浏览器的同源策略你是怎样理解的呢? - 王泥煤的回答 - 知乎,另外后面华为开发社区号的回答也不错。
三、如何进行跨域访问
解决跨域问题有四种方法:
- 架设服务器代理(浏览器请求同源服务器,再由同源服务器进行外部服务);
- JSONP(思想是通过添加Script元素,向服务器请求JSON数据);
- WebSocket协议(该协议不遵循同源策略);
- 跨源资源分享(CORS,Cross-Origin Resource Sharing)
这四种方法,详情可见浏览器同源政策及其规避方法——阮一峰的网络日志
四、跨源资源分享CORS
跨源资源共享 (CORS) (或通俗地译为跨域资源共享)是一种基于HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它origin(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的”预检”请求。在预检中,浏览器发送的头中标示有HTTP方法和真实请求中会用到的头。
CORS允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
五、SpringBoot项目中使用CORS
参考SpringBoot 实现前后端分离的跨域访问(CORS)
方式1:返回新的CorsFilter(全局跨域)
方式2:重写WebMvcConfigurer(全局跨域)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package com.hehe.yyweb.config;
public class GlobalCorsConfig {
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
//重写父类提供的跨域请求处理的接口
public void addCorsMappings(CorsRegistry registry) {
//添加映射路径
registry.addMapping("/**")
//放行哪些原始域
.allowedOrigins("*")
//是否发送Cookie信息
.allowCredentials(true)
//放行哪些原始域(请求方式)
.allowedMethods("GET","POST", "PUT", "DELETE")
//放行哪些原始域(头部信息)
.allowedHeaders("*")
//暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
.exposedHeaders("Header1", "Header2");
}
};
}
}方式3:使用注解(@CrossOrigin)(局部跨域)
方式4:手工设置响应头(HttpServletResponse )(局部跨域)
六、本地实操
未配置CORS通过web访问服务端接口时浏览器端的错误:
http请求头
配置了CORS且请求成功的请求头
可以看到配置 Access-Control-Allow-Origin: *
,放行所有原始域。