一、先搞懂“跨域”是啥——浏览器的“安全小卫士”
想象你正在用浏览器访问一个网站(比如 https://example.com
),这个网站想从另一个地址(比如 https://api.other.com/data
)拉取数据(比如用户评论)。这时候,浏览器会突然跳出来阻止:“不行!这两个地址不一样,我得先问问你同不同意!”——这就是跨域问题。
为什么浏览器要管这个?
因为浏览器有个“同源策略”(Same-Origin Policy),它就像小区的保安:只允许你(当前网站)访问和自己“同小区、同楼号、同门牌”的资源(协议、域名、端口完全一致)。如果想访问“别人家”的资源(比如从 example.com
访问 other.com
),保安就会拦住你,防止坏人偷数据。
但现实中,很多场景需要跨域访问,比如:
- 前端网页用
https://前端域名.com
展示页面,但数据要从https://后端接口.com
拿; - 调用第三方API(比如地图服务、支付接口);
- 微信小程序调用外部服务。
这时候,“跨域”就成了开发的绊脚石。
二、CORS:浏览器和服务器的“协商通行证”
为了解决跨域问题,浏览器和服务器发明了一套“暗号系统”,叫CORS(Cross-Origin Resource Sharing,跨域资源共享)。它的核心逻辑是:浏览器先拦住请求,让服务器表态“是否允许跨域”,再决定是否放行。
具体流程分两步:
-
简单请求(比如GET、POST带简单头部):浏览器直接发请求,但在请求头里塞一个
Origin: https://前端域名.com
(告诉服务器“我是谁”)。服务器收到后,如果同意跨域,就在响应头里加Access-Control-Allow-Origin: https://前端域名.com
(相当于盖章:“允许这个来源访问”)。浏览器看到这个盖章,就放行数据。 -
非简单请求(比如PUT、DELETE,或者带自定义头部):浏览器会先发一个“试探请求”(叫
OPTIONS
请求),问服务器:“我想发个XXX请求,你允许吗?”服务器回复:“允许/不允许,以及允许哪些头、哪些方法”。如果服务器同意,浏览器才会正式发真正的请求。
问题来了:如果服务器没正确配置CORS(比如没加Access-Control-Allow-Origin
),浏览器就会直接拦截响应,哪怕服务器明明返回了正确的数据!
三、CORS代理:给浏览器“绕路走”的秘密通道
如果服务器不支持CORS(比如是个老旧系统,或者第三方API没做跨域配置),怎么办?这时候就需要CORS代理出场了!
CORS代理本质上是一个“中间人”服务器,它的作用是:
- 代替浏览器去请求目标数据:前端不直接访问
https://api.other.com/data
(会被浏览器拦住),而是访问CORS代理(比如https://cors-proxy.com/?target=https://api.other.com/data
)。 - 代理服务器去拿数据:CORS代理收到请求后,自己向
https://api.other.com/data
发请求(因为代理服务器没有浏览器的“同源策略”限制,可以直接访问任何地址)。 - 把数据加上CORS头再返回给浏览器:代理服务器拿到数据后,在响应头里加上
Access-Control-Allow-Origin: *
(或者指定允许的前端域名),再返回给前端浏览器。这时浏览器看到响应头里有“允许跨域”的标志,就放行数据了!
举个栗子🌰:
假设你想从一个不支持CORS的天气API(https://weather.api.com/data
)拿数据,但直接访问会被浏览器拦截。你可以:
- 前端代码里不直接请求
https://weather.api.com/data
,而是请求https://cors-proxy.com/?url=https://weather.api.com/data
; - CORS代理服务器收到请求后,自己向
https://weather.api.com/data
发请求,拿到天气数据; - 代理服务器在返回数据时,加上
Access-Control-Allow-Origin: *
的响应头; - 浏览器看到这个头,就允许你的网页使用天气数据了!
四、CORS代理的优缺点——方便但有代价
优点:
- 快速解决跨域问题:不用等后端改代码或者联系第三方API配置CORS,自己搭个代理就能用。
- 兼容性强:适合老项目、第三方服务或者无法修改服务器配置的场景。
- 灵活控制:可以自己决定代理哪些请求、加哪些响应头(比如限制允许的域名,而不是直接开
*
)。
缺点:
- 代理服务器可能成为瓶颈:如果请求量很大,代理服务器的压力会很大(毕竟所有跨域请求都要经过它)。
- 安全性风险:如果代理服务器没做好防护(比如允许任意URL转发),可能被滥用成“爬虫工具”或者“攻击跳板”(比如有人通过你的代理去攻击其他网站)。
- 隐私问题:代理服务器会看到所有经过它的请求和响应数据(包括用户敏感信息),所以一定要用可信的代理服务!
五、怎么用CORS代理?——手把手教你搭一个
如果你只是想临时测试或者自己开发用,可以用现成的免费CORS代理(比如 https://cors-anywhere.herokuapp.com/
),但要注意:
- 免费服务可能有请求限制;
- 别拿它干坏事(比如爬取禁止爬取的数据),否则可能被封IP。
如果想自己搭一个,用Node.js写一个简单的代理只需要几行代码(以express
框架为例):
const express = require('express');
const request = require('request');
const app = express();
// 允许所有来源访问(生产环境应该限制具体域名!)
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
// 代理所有请求到目标URL
app.get('/proxy', (req, res) => {
const targetUrl = req.query.url; // 从参数里拿目标地址,比如 ?url=https://api.other.com/data
if (!targetUrl) {
return res.status(400).send('请传入url参数');
}
// 把请求转发到目标地址,并把响应返回给浏览器
req.pipe(request(targetUrl)).pipe(res);
});
app.listen(3000, () => {
console.log('CORS代理已启动,访问 http://localhost:3000/proxy?url=目标地址');
});
用法示例:
前端代码里不再直接请求 https://api.other.com/data
,而是请求 http://localhost:3000/proxy?url=https://api.other.com/data
。这样,浏览器会认为自己在访问 localhost
(同源),而代理服务器会偷偷去拿真实数据并返回。
六、总结:CORS代理是“应急神器”,但别滥用
CORS代理就像一把“万能钥匙”,能快速解决跨域问题,但它不是长久之计。理想情况下,应该让后端服务正确配置CORS(比如只允许信任的前端域名访问),或者通过后端中转数据(前端→自己的后端→第三方API,这样浏览器只会看到“同源”请求,彻底避开跨域问题)。