目录
一、跨域是如何产生的?
跨域问题产生的原因主要是浏览器的同源策略(Same-Origin Policy)。同源策略是一种安全机制,用于防止不同来源的网页之间的恶意操作。
源由协议(protocol)、主机(host)和端口(port)组成。即使是小的差异也会被视为不同的源:
- 协议: HTTP 和 HTTPS 被视为不同的协议。
- 主机:
example.com
和api.example.com
是不同的主机。 - 端口:
example.com:80
和example.com:8080
是不同的端口。
只要有一个不同,那么就产生了跨域!
二、跨域产生的场景
Vue项目运行在 http://127.0.0.1:80 上,SpringBoot项目运行在 http://127.0.0.1:8080 上,我们的Vue项目需要发起请求到SpringBoot上获取资源,假设发起请求的URL为:http://127.0.0.1:8080/user/list,因为发起请求的端口与Vue项目运行的端口不一致的原因,浏览器会受到同源策略的限制,阻止这种请求,此时就会遇到跨域问题。
三、跨域的前置知识
1. 简单请求
GET
或 POST
方法,且不包含特殊的请求头部(除了 Accept
、Accept-Language
、Content-Language
和 Content-Type
的特定值,其他都为特殊的请求头),则浏览器会直接发送请求,不会进行预检请求。
注:Content-Type
头部的简单值包括:
application/x-www-form-urlencoded
multipart/form-data
text/plain
2. 非简单请求
使用了 PUT
、DELETE
方法或带有自定义请求头部,浏览器会先发送一个预检请求(OPTIONS 请求)来确认服务器是否允许实际的跨域请求。
注:预检请求是请求方法为 “OPTIONS” 的请求,只有预检请求通过了,浏览器才会把实际的请求发送到后端。
四、如何解决跨域问题
1.前端Vue项目可以配置代理(Proxy)
在项目的根路径下的 vue.config.js 添加如下配置
module.exports = {
devServer: {
proxy: {
'/api': {
target: `http://127.0.0.1:8080`,
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
}
}
这样,所有以 /api
开头的请求会被代理到 http://127.0.0.1:8080
各位会不会有这样的疑问,为什么配置代理就可以绕过浏览器的跨域问题?
-
统一源: 代理服务器和前端应用通常运行在同一个源下,浏览器对同源策略的限制不再适用,因为所有的请求都首先被发送到代理服务器,而不是直接发送到目标服务器。
-
转发请求: 代理服务器负责将请求转发到目标服务器并将响应返回给客户端。浏览器与代理服务器之间的通信是同源的,所以不受同源策略的限制。
注:前端应用中的代理配置通常仅用于开发环境。在生产环境中,前端应用直接与服务器通信,通常不再使用代理。
2.后端SpringBoot项目配置CORS跨域策略
在一个配置文件下注册CORS这个bean即可
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
//允许所有域名进行跨域调用
config.addAllowedOriginPattern("*");
//允许跨域发送cookie
config.setAllowCredentials(true);
//放行全部原始头信息
config.addAllowedHeader("*");
//允许所有请求方法跨域调用
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
不知道大家有没有跟我一样的疑问,跨域是浏览器的同源策略问题,前端配置了代理就能绕过跨域,为什么后端还要配置CORS策略?
- 生产环境的需要。代理不是全局解决方案,前端代理解决的是开发过程中跨域的问题。在生产环境中,服务器需要自行处理跨域请求,以确保应用能够正常运作。
-
处理复杂场景。CORS 允许处理复杂的跨域场景,如预检请求(使用了非简单头部或方法的请求)。CORS 策略允许服务器响应这些预检请求并确定是否允许实际请求。
-
确保安全性。 配置 CORS 策略可以防止恶意网站通过脚本发送请求,从而对服务器施加攻击或滥用资源。只有经过授权的域名才能访问服务器的资源,这有助于防止潜在的安全漏洞。
-
支持跨域请求。浏览器的同源策略限制了客户端(浏览器)直接访问不同源的资源。如果服务器没有配置 CORS 策略,即使前端应用试图通过浏览器发起跨域请求,浏览器也会阻止这些请求,导致应用无法正常工作。【这里一会重点说一下(情况分析)】
五、情况分析
在触发了跨域问题的前提下,服务器没有配置 CORS 策略,如果浏览器发起请求(以一个简单请求和非简单请求为例),此时是怎样处理的呢?
简单请求:前端没有配置代理。发起一个简单请求到后端,后端能够接收到请求并进行处理,即使前端没有配置代理,后端没有配置 CORS,后端还是可以正常处理请求并生成响应,浏览器会收到后端的响应,【但由于没有适当的 CORS 头部(Access-Control-Allow-Origin),前端应用无法访问响应的内容,具体表现为前端应用中的 JavaScript 代码无法读取响应数据,通常会触发一个跨域错误(No 'Access-Control-Allow-Origin' header is present on the requested resource.)】(浏览器同源策略的具体表现);前端配置了代理。那么可以正常解析响应请求,由于请求是从同源的代理服务器发起的,所以浏览器的同源策略不会阻止这个请求。
非简单请求:对于非简单请求,前端配不配置代理,都会发送一个预检请求(OPTIONS),来检查是否允许跨域请求,而后端没有配置CORS跨域策略(配置了会返回适当的 CORS 头部,如 Access-Control-Allow-Methods
和 Access-Control-Allow-Headers
),所以这个预检请求不通过,那么实际请求也就不会发起。
六、总结
后端服务器配置了CORS跨域策略,即可一劳永逸,前端无需配置跨域。因为对于简单请求来说,浏览器的同源策略,实际上是解析请求响应头上的Access-Control-Allow-Origin是否是当前域名能访问的(*代表任何域名都可以访问);而对于非简单请求,因为配置了CORS跨域策略,预检请求通过,实际的请求发起,后端在响应时设置了 Access-Control-Allow-Origin
,
浏览器会允许前端应用访问响应数据。