小白也能懂!跨域问题到底是啥,咋解决?
大家好呀!最近有朋友问我:"我做了个小网页,想拿别人网站的数据(比如天气 API),结果浏览器报错说'跨域了',这啥意思啊?" 今天就用大白话给大家讲明白 ------ 跨域问题到底是啥,以及怎么解决它。
一、先搞懂:啥是 "跨域"?
要理解 "跨域",得先知道一个词:同源。
"同源" 就是说两个网址的「协议」「域名」「端口号」这三样必须完全一样!少一个一样都不行。
举个栗子,假设你的网页地址是 a.com:8080(协议是 http,域名是a.com,端口 8080),那下面这些情况就是「跨域」:
| 你的网址 | 要访问的网址 | 为啥跨域? |
|---|---|---|
| a.com:8080 | a.com:8080 | 协议不一样(http≠https) |
| a.com:8080 | b.com:8080 | 域名不一样(a.com≠b.com) |
| a.com:8080 | a.com:3000 | 端口不一样(8080≠3000) |
简单说:只要两个网址不是 "同源",你从 A 网址去拿 B 网址的数据,浏览器就会拦着你,这就是跨域问题。
二、为啥浏览器要 "拦着"?------ 同源策略
你可能会问:"浏览器为啥这么严?我就是想拿点数据而已啊!"
这其实是浏览器的一个安全规则,叫「同源策略」,目的是保护你的信息安全。
再举个栗子:你登录了淘宝(taobao.com),浏览器会存一个 "登录凭证"(cookie)。如果没有同源策略,随便一个小网站(bad.com)都能偷偷拿你淘宝的登录凭证,那你的账号不就危险了?
所以「同源策略」就像你家的门锁 ------ 只让 "自己人"(同源网址)进,不让 "外人"(跨域网址)随便碰你家东西(数据)。
三、3 个小白也能懂的解决办法
知道了啥是跨域、为啥有跨域,接下来就是重点:怎么解决?
下面给大家讲 3 个最常用、最简单的办法,不同场景选不同的就行~
办法 1:让后端 "开门"------ CORS(最推荐)
这是现在最常用的办法,核心是:让你要访问的后端(比如天气 API 的服务器)主动说 "允许你这个网址来拿数据" 。
怎么实现?其实不用前端操心,让后端在返回数据时,多带一个 "特殊头信息" 就行。
举个后端的简单例子(用 Node.js 写的,其他语言逻辑一样):
php
// 后端代码( Node.js + Express )
const express = require('express');
const app = express();
// 关键:加这行代码,
app.use(cors({
// 允许所有域名跨域访问
origin:"*",
// 允许所有 HTTP 方法跨域访问,这里默认是加了预检请求
methods:["GET","POST","PUT","DELETE"],
// 允许所有请求头跨域访问
allowedHeaders:["Content-Type","Authorization"],
}))
// 后端接口:返回天气数据
app.get('/weather', (req, res) => {
res.send({ city: '北京', temp: '25℃' }); // 给前端的数据
});
app.listen(3000);
前端不用改任何代码,直接正常发请求就行:
javascript
// 前端代码(普通JS)
fetch('http://b.com:3000/weather') // 访问后端接口
.then(res => res.json())
.then(data => console.log(data)); // 成功拿到天气数据!
适用场景:你能联系到后端开发者(比如公司内部项目),让他们加这行配置。
办法 2:借 "script 标签" 的光 ------ JSONP(老项目常用)
有些老项目后端没法改,那可以用 JSONP。它的原理很有意思:浏览器的 script 标签不受同源策略限制(比如你能在自己网页里引百度的 JS 文件)。
实现步骤也很简单:
- 前端先定义一个 "回调函数"(用来接收数据);
- 用 script 标签去请求后端接口,并且把 "回调函数名" 传给后端;
- 后端返回一段 JS 代码,内容是 "调用这个回调函数,把数据当参数传进去"。
举个例子:
javascript
// 1. 前端定义回调函数(拿到数据后要做的事)
function handleWeather(data) {
console.log('拿到天气了:', data); // 比如打印数据
}
// 2. 用script标签请求后端接口,传回调函数名
const script = document.createElement('script');
// 后端接口地址 + ?callback=回调函数名
script.src = 'http://b.com:3000/weather?callback=handleWeather';
document.body.appendChild(script); // 插入页面,发起请求
// 3. 后端返回的内容会是:handleWeather({city:'北京', temp:'25℃'})
// 浏览器执行这段JS,就会调用我们定义的handleWeather,拿到数据!
后端代码(Node.js):
javascript
app.get('/weather', (req, res) => {
const callbackName = req.query.callback; // 拿到前端传的回调函数名
const weatherData = { city: '北京', temp: '25℃' }; // 要返回的数据
// 关键:返回"回调函数调用"的JS代码
res.send(`${callbackName}(${JSON.stringify(weatherData)})`);
});
注意:JSONP 只能发 GET 请求,不能发 POST 请求,所以适合拿数据,不适合提交数据。
办法 3:前端自己 "搭个桥"------ 代理服务器(本地开发用)
如果你是本地开发(比如用 Vue/React 写项目),后端还没配置 CORS,那可以用 "代理服务器"。
原理很简单:浏览器有同源策略,但服务器之间没有! 所以我们让前端先把请求发给 "自己的代理服务器",再让代理服务器去请求后端,最后代理服务器把数据返回给前端。
以 Vue 项目为例,只需要改一下配置文件(vue.config.js):
java
// vue.config.js 配置
module.exports = {
devServer: {
proxy: {
// 只要前端请求以 /api 开头,就走代理
'/api': {
target: 'http://b.com:3000', // 后端接口的真实地址
changeOrigin: true, // 告诉后端"我是从你允许的网址来的"(伪装)
pathRewrite: {
'^/api': '' // 把请求里的 /api 去掉(比如 /api/weather → /weather)
}
}
}
}
};
然后前端请求时,直接写 /api/weather 就行:
kotlin
// 前端代码(Vue里)
this.$axios.get('/api/weather') // 看似请求自己的代理,实际会转发到后端
.then(res => console.log(res.data));
适用场景:本地开发时临时用,不用麻烦后端改配置。
四、总结一下
- 跨域就是:浏览器不让不同 "源" 的网址互相拿数据,为了安全;
- 解决办法选哪个?
-
- 能联系后端 → 用 CORS(最推荐);
-
- 后端没法改,只需要 GET 数据 → 用 JSONP;
-
- 本地开发临时用 → 用代理服务器。
其实跨域问题没那么难,关键是理解 "同源策略" 的初衷,然后根据场景选对方法~ 大家可以动手试试上面的例子,很快就能掌握啦!