赞
踩
CORS(Cross-Origin Resource Sharing,跨域资源共享)是一种机制,允许在浏览器中向其他域(不同源)发送 XMLHttpRequest 请求,即跨域请求。在默认情况下,浏览器限制跨域请求,以防止潜在的安全风险,如CSRF攻击(跨站请求伪造)。
但是,CORS 通过一系列的 HTTP 头部字段来进行通信,使得服务器可以告知浏览器哪些跨域请求是安全的,从而实现跨域资源共享。
同源指的是协议相同、域名相同和端口相同。当网页尝试从一个源的域、协议、端口中的任何一个与当前页面不同的资源进行请求时,就会触发跨域问题。
通过使用下面这些 HTTP 头部字段,CORS 机制允许服务器和客户端之间在跨域请求时进行通信,并确保安全性。服务器可以根据请求中的 Origin 头部字段来判断是否允许跨域访问,并设置相应的 CORS 响应头来控制跨域请求的行为。
跨域通信相关字段表
字段 | 作用 |
---|---|
Origin | 指示请求的来源地址。 |
Access-Control-Allow-Origin | 服务器端设置的响应头,用于指示允许访问资源的来源地址。可以是特定的域名、通配符(*)表示允许所有来源,或者一系列域名的白名单。 |
Access-Control-Allow-Methods | 服务器端设置的响应头,用于指示允许的 HTTP 方法,如 GET、POST、PUT、DELETE 等。 |
Access-Control-Allow-Headers | 服务器端设置的响应头,用于指示允许的 HTTP 请求头,如 Content-Type、Authorization 等。 |
Access-Control-Allow-Credentials | 服务器端设置的响应头,用于指示是否允许发送 Cookie 和认证信息。 |
Access-Control-Request-Headers | 客户端发起预检请求时,用于指示实际请求中会使用的自定义请求头。 |
Access-Control-Request-Method | 客户端发起预检请求时,用于指示实际请求中会使用的 HTTP 方法。 |
Postman 不受同源策略的限制,因此它可以发送跨域请求而不受到浏览器的拦截。
后端采用了restful风格的url,按自己需求进行更改。服务端配置在8080端口。
@RequestMapping("/user/{id}")
public Map<String, String> testCORS(@PathVariable String id, @RequestHeader HttpHeaders httpHeaders) {
System.out.println("Origin:" + httpHeaders.getOrigin());
System.out.println("成功测试CORS: id " + id);
HashMap<String, String> map = new HashMap<>(); //将origin字段以map形式返回去
map.put("Origin", httpHeaders.getOrigin());
return map;
}
后端跨域解决方案之一,采用配置Spring MVC的跨域请求信息,按匹配放行:
package com.song.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @author song * @version 0.0.1 * @date 2024/4/7 19:03 */ @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") //匹配所有请求 .allowedOrigins("127.0.0.1:8081") //放行的Origin .allowedMethods("*"); //放行的方法 } }
在前文中既然知道了服务器端是根据origin字段进行跨域判断的,那我们在Postman构建一个带Origin字段的header。这个测试为后端没有配置CORS请求映射的测试情况。
上面请求中表现了请求地址、请求头、响应头、响应体。可以看出现在的请求是同源的,相当于使用浏览器和后端直接通信,不经过脚本等方式。
同源策略是针对通过脚本等方式进行的跨域请求的安全限制,而直接在地址栏输入地址是用户主动行为,不受同源策略的限制。在这种情况下,浏览器会默认认为用户信任目标地址,因此不会将其视为跨域请求。不过有一些其他安全性较高操作也会进行限制。
从上方的响应体的返回数据来看,普通请求不会携带Origin字段,后端没有配置CORS则不会返回字段Access-Control-Allow-Origin、Access-Control-Request-Method、Access-Control-Request-Headers。
现在把后端的跨域配置注释掉。测试跨域情况下,在没有配置跨域时,能不能成功。
上面我们了解到,跨域的判断方式是根据Origin字段进行判断的。那么我们构造一个带有Origin字段的请求头,模拟跨域通信。
下方的实验结果分析来看,我们在Headers中添加了一个Origin字段127.0.0.1:8081
,相当于有个请求需要从这个Origin地址转发到服务器端地址127.0.0.1:8080
。实际中该字段由浏览器检测到跨域请求时自动添加的。
后端由于没有配置跨域,所以并没有返回跨域相关字段。在返回结果中,成功返回Origin字段,但是不代表后端的跨域没有起作用。 Postman由于不会受到浏览器的拦截,所以会显示后端的信息。
》》》再次测试Vue发送跨域请求,同样在后端没有配置跨域信息情况下:
可以发现,返回403错误,表示服务器有能力处理这次请求,但是拒绝授权访问。
为什么采用Postman模拟跨域的时候,后端没有设置CORS配置却可以直接访问呢?但是使用Vue却不可以呢?
跨域究竟是后端还是浏览器搞的鬼,答案:浏览器
后端会处理这份请求,但是浏览器会把返回的响应体直接过滤掉,虽然返回了200,但是浏览不给你这份数据。
将这段代码加入Spring MVC的自定义配置中。
package com.song.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @author song * @version 0.0.1 * @date 2024/4/7 19:03 */ @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") //匹配所有请求 .allowedOrigins("127.0.0.1:8081") //放行的Origin .allowedMethods("*"); //放行的方法 } }
请求头采用默认的请求头,请求地址依旧后端的请求地址。在响应体中则发生了变化。
可以发现,响应头中多了几个字段,依次是Origin、Access-Control-Request-Method、Access-Control-Request-Headers。从上面的对照表可以看出,这些分别表示请求源地址、访问控制允许的方法、访问控制允许的请求头。
不跨域情况下Origin字段始终为空。
浏览器中直接测试该请求,返回结果和上面一致。
Access-Control-Allow-Origin: 127.0.0.1:8081
。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。