前端新手也能看懂的跨域问题详解
在前端开发中,我们经常会听到“跨域问题”。尤其是在本地调试前端和后台接口时,浏览器突然抛出一堆报错信息,比如:
Access to XMLHttpRequest at '[http://api.xxx.com/data](http://api.xxx.com/data)' from origin '[http://localhost:8080](http://localhost:8080)' has been blocked by CORS policy...
这到底是什么鬼?别慌,今天我们就一口气搞清楚什么是跨域、为什么会出现跨域、怎么解决跨域!
一、什么是“跨域”?
跨域指的是:浏览器因为安全限制,阻止了网页对不同源(域名/IP/端口号不同)的请求。
所谓“源”,就是由以下三部分组成的:
- 协议(http/https)
- 域名(或IP)
- 端口号
只要其中任意一项不同,就叫做“不同源”,比如:
地址 | 和 http://localhost:8080 比较 |
是否同源 |
---|---|---|
http://localhost:8080 |
完全相同 | 同源 |
http://localhost:3000 |
端口不同 | 跨域 |
https://localhost:8080 |
协议不同 | 跨域 |
http://127.0.0.1:8080 |
IP不同 | 跨域 |
http://api.example.com |
域名不同 | 跨域 |
二、为什么会有跨域限制?
这是浏览器的同源策略(Same-Origin Policy)在起作用。
这个策略是为了保护用户的信息安全,防止恶意网站读取你在其他网站上的隐私数据(比如你登陆了 A 网站,但正在访问 B 网站,B 网站偷偷用 JS 请求 A 网站获取你的个人信息,这就很危险了)。
所以,浏览器默认就限制了跨域请求。
三、哪些操作会触发跨域?
最常见的触发方式是通过前端的 JavaScript 发送请求,例如:
fetch('http://api.xxx.com/data') // 如果地址和页面地址不是同源,就会被拦截
其他还有:
- 使用
XMLHttpRequest
或axios
- 页面内嵌 iframe
- 加载外部的脚本、字体、样式(但有些资源不受限制)
四、怎么解决跨域问题?
跨域不是不能请求,而是默认不允许。我们可以通过一些方式让浏览器**“信任”**这次跨域请求。
方法一:CORS(跨源资源共享)【推荐】
这是最常见也最官方的方式。
需要后端在响应头中加上允许跨域的字段:
Access-Control-Allow-Origin: http://localhost:8080
如果允许所有域访问,也可以写:
Access-Control-Allow-Origin: *
完整示例(Node.js Express 后端):
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*'); // 允许所有域访问
res.setHeader('Access-Control-Allow-Methods', 'GET,POST'); // 允许的方法
res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // 允许的请求头
next();
});
方法二:通过代理绕过浏览器
在开发环境中,你也可以设置一个本地代理,让浏览器以为你访问的是同源。
比如用 vite
或 webpack
设置代理:
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'http://api.xxx.com',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
}
你在前端请求 /api/data
,实际上是请求 http://api.xxx.com/data
,从而绕过跨域限制。
方法三:JSONP(已过时,只支持GET)
是一种早期的跨域方案,用 <script>
标签加载数据,原理是浏览器允许跨域加载 JS 文件。但现在一般不推荐,功能有限,且不支持 POST。
五、总结一句话
跨域问题是浏览器安全机制限制的结果,我们可以通过配置 CORS 或使用代理来解决。
FAQ:你可能还想问
跨域只在浏览器中出现吗?
是的,Node.js 端、Postman、curl 请求都不会受到“同源策略”的影响。后端一定要支持 CORS 吗?
如果你要前端直接访问后端 API,那后端必须支持;否则只能通过代理。是不是所有请求都会被预检?
不是,简单请求不会,比如 GET 请求且 Content-Type 是application/x-www-form-urlencoded
。