什么是跨域?跨域怎么解决?跨域解决的是什么问题?
跨域定义:
“跨域”,首先需要明确它的核心场景 ——浏览器端的安全限制,即浏览器为保护用户数据安全,默认禁止一个网站的 JavaScript 代码去请求另一个 “不同域” 的资源(如数据、图片、脚本等)。这种限制被称为 “同源策略”(Same-Origin Policy),而 “跨域” 就是 “突破同源策略、实现不同域间资源请求” 的行为。
一、什么是 “同源”?
“同源” 是浏览器判断是否允许资源请求的核心标准,需同时满足以下 3 个条件:
- 协议相同:如都是
http
、https
(http://a.com
和https://a.com
不同源); - 域名相同:如都是
a.com
(a.com
和b.com
不同源,a.com
和sub.a.com
也不同源,后者是子域名); - 端口相同:如都是默认的
80
(http)或443
(https)(a.com:8080
和a.com:80
不同源)。
只要有一个条件不满足,就属于 “不同域”,此时浏览器会触发同源策略限制,阻止跨域请求。
二、为什么会有 “跨域问题”?
同源策略是浏览器的 “安全盾”,目的是防止恶意网站窃取用户数据。举个例子:
- 你登录了银行网站
https://bank.com
(浏览器会保存银行的登录 Cookie); - 同时打开了一个恶意网站
https://evil.com
; - 如果没有同源策略,
evil.com
的 JS 代码可以直接请求bank.com
的 “查询余额” 接口,浏览器会自动带上你的银行 Cookie,导致余额被恶意获取。
正是同源策略的限制,evil.com
无法直接请求 bank.com
的资源,从而保护了你的数据安全。但这也带来了 “麻烦”:合法的跨域需求无法实现(如前端项目 http://localhost:8080
要请求后端 API http://api.example.com
),这就是 “跨域问题” 的本质。
三、常见的跨域场景
日常开发中,以下情况都属于跨域,会触发浏览器限制:
四、如何解决跨域问题?
解决跨域的核心思路是 “让浏览器允许不同域的请求”,常见方案有以下 3 种:
1. 后端配置 CORS(最常用、最标准)
CORS(Cross-Origin Resource Sharing,跨域资源共享)是 W3C 标准,本质是后端在响应头中添加允许跨域的规则,告诉浏览器 “这个请求是安全的,可以放行”。
# 允许的请求源(* 表示允许所有源,生产环境建议指定具体域名,如 http://localhost:8080)
Access-Control-Allow-Origin: http://localhost:8080
# 允许的请求方法(如 GET、POST、PUT 等)
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
# 允许的请求头(如 Content-Type、Authorization 等)
Access-Control-Allow-Headers: Content-Type, Authorization
浏览器收到响应后,看到这些头信息,就会允许前端读取响应数据,从而解决跨域。
2. 前端配置代理(开发环境常用)
在开发阶段(如用 Vue、React 脚手架),可以通过 “代理服务器” 转发请求,绕过浏览器的同源策略限制。原理是:
- 浏览器只限制 “前端直接请求后端”,但不限制 “前端请求本地代理服务器”(因为同源,都是
localhost
); - 代理服务器是后端服务,没有同源策略限制,可以自由请求目标后端接口;
- 流程:前端 → 本地代理服务器 → 目标后端 → 本地代理服务器 → 前端。
以 Vue 为例,在 vue.config.js
中配置代理:
module.exports = {devServer: {proxy: {// 匹配所有以 /api 开头的请求'/api': {target: 'http://api.example.com', // 目标后端地址changeOrigin: true, // 让代理服务器伪装成目标域名(解决后端可能的域名校验)pathRewrite: { '^/api': '' } // 去掉请求路径中的 /api(如 /api/user → /user)}}}
}
配置后,前端请求 /api/user
,就会被代理到 http://api.example.com/user
,避免跨域。
3. JSONP(兼容性好,但有局限)
JSONP 是早期的跨域方案,利用了 “<script>
标签没有同源策略限制” 的特性(如网页中引入其他域的 JS 脚本是允许的)。原理是:
- 前端定义一个回调函数
handleData(data)
,用于接收后端数据; - 前端动态创建
<script>
标签,src 指向后端接口,并带上回调函数名:http://api.example.com/data?callback=handleData
; - 后端返回 JS 代码:
handleData({ "name": "张三" })
; - 浏览器执行该 JS 代码,调用
handleData
函数,前端即可拿到数据。
局限:只能支持 GET 请求(因为 <script>
标签只能发 GET 请求),且安全性较低(可能存在 XSS 风险),目前已逐渐被 CORS 取代。
五、针对前两种方法进行实战演示跨域解决
当你看到错误信息 has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
时,这意味着浏览器因为跨域资源共享(CORS)策略阻止了你的请求。具体原因是:被请求的服务器没有在响应头中包含 Access-Control-Allow-Origin
字段,导致浏览器判定该跨域请求不安全,从而拒绝访问。
对于 后端使用 springboot(Java)
使用java(spring boot)进行开发进行演示可以有以下几种:
1.使用@CrossOrigin注解
@CrossOrigin(origins = "http://localhost:5173"),替换成你的前端ip+端口即可
使用 @CrossOrigin
注解,对单个控制器或方法单独配置跨域,优先级高于全局配置:
2.全局跨域配置(推荐)
通过实现 WebMvcConfigurer
接口,配置全局跨域规则,对所有接口生效:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 对所有接口生效.allowedOrigins("http://localhost:8081", "https://example.com") // 允许的前端域名,*表示允许所有(生产环境不推荐).allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的请求方法.allowedHeaders("*") // 允许的请求头.exposedHeaders("token") // 允许前端获取的响应头(默认只能获取简单响应头).allowCredentials(true) // 是否允许携带cookie(需配合具体域名,不能用*).maxAge(3600); // 预检请求的缓存时间(秒),减少重复预检请求}
}
关键参数说明:
allowedOrigins
:指定允许的前端域名,生产环境建议明确指定(如https://www.xxx.com
),避免使用*
(安全风险)。allowCredentials(true)
:若前端需要携带 Cookie 或 Token 等认证信息,必须设置为true
,且allowedOrigins
不能为*
。maxAge
:预检请求(OPTIONS)的缓存时间,设置后浏览器在有效期内不会重复发送预检请求,优化性能。
对于前端使用Vue 项目
配置代理(vue.config.js)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'// https://vite.dev/config/
export default defineConfig({plugins: [vue()],server:{proxy:{// 配置第一个代理规则:匹配所有以 /test 开头的请求'/sse':{target:"http://localhost:8081",// 目标服务器地址(后端接口的域名或IP)changeOrigin:true,// 开启代理:将请求头中的 host 改为目标服务器的 hostrewrite:(path)=>path.replace(/^\/sse/, '') // 将路径中的 /test 替换为空// secure:false, // 当 target 是 https 时,是否验证 SSL 证书}// 配置第二个规则(如果需代理多个域名)},
六、关键注意点
- 跨域只存在于浏览器端:后端之间的请求(如 Java 调用 Python 接口)没有同源策略限制,无需处理跨域;
- OPTIONS 预检请求:当前端发送 “非简单请求”(如 POST 请求且 Content-Type 为 application/json、带自定义头 Authorization)时,浏览器会先发送一个
OPTIONS
请求(预检请求),询问后端 “是否允许该请求”,后端需正确响应 OPTIONS 请求才能继续; - Cookie 跨域:默认情况下,跨域请求不会携带 Cookie,若需携带,需满足两个条件:
- 后端响应头添加
Access-Control-Allow-Credentials: true
; - 前端请求时设置
withCredentials: true
(如 Axios 中配置axios.defaults.withCredentials = true
),且后端Access-Control-Allow-Origin
不能为*
(需指定具体域名)。
- 后端响应头添加
总结:跨域是浏览器同源策略导致的安全限制,解决跨域的核心是 “让浏览器认可请求的安全性”,推荐在生产环境用 CORS、开发环境用代理,JSONP 仅作为兼容性补充。