跨域彻底讲透
跨域彻底讲透。
一、 跨域的定义
跨域指的是:当一个 Web 应用(位于一个域名下)试图去请求另一个域名下的资源时,如果这两个域名的协议、域名、端口有任何一项不相同,浏览器就会认为这是跨源的,并默认禁止这种请求。
浏览器的同源策略
同源策略是浏览器的一个最核心、最基础的安全功能。它规定:只有当协议、域名、端口三者完全相同时,才被认为是“同源”的,否则就是“跨域”或“跨源”。
- 跨源例子:
https://www.example.com
→http://www.example.com
(协议不同,HTTP vs HTTPS)https://www.example.com
→https://api.example.com
(域名不同,主域 vs 子域)https://www.example.com
→https://www.example.com:8080
(端口不同,443 vs 8080)
当发生跨域时,浏览器会拦截 Ajax 请求: 使用
XMLHttpRequest
或Fetch API
发起的请求。
二、为什么?—— 为什么要存在跨域限制?
这是一个“浏览器多管闲事”的行为吗?绝对不是。这是为了安全。
假设没有同源策略,会非常可怕:
- 你登录了银行网站(
https://my-bank.com
),浏览器保存了你的 Cookie 会话。 - 你无意中访问了一个恶意网站(
https://evil-site.com
)。 - 这个恶意网站上的脚本,可以用你的身份悄悄向
https://my-bank.com/transfer?to=hacker&amount=1000000
发起 AJAX 请求。 - 因为你的浏览器带着
my-bank.com
的 Cookie,银行服务器会认为这是你的合法操作,从而执行转账。
这就是可怕的 CSRF(跨站请求伪造) 攻击。同源策略极大地增加了这种攻击的难度
总结:同源策略的目的是为了保护用户信息安全和隐私,防止恶意网站窃取数据或冒充用户身份。
三、解决跨域的常见方案
既然跨域是浏览器搞的鬼,那我们的解决方案就是 “想办法让浏览器点头放行”。
以下是主流且高效的解决方案,从上到下推荐程度递减:
方案一:(跨域资源共享)—— 官方终极方案
这是 W3C 标准,也是现代浏览器最推荐、最主流的跨域解决方案。它需要服务器和浏览器共同配合。
原理:服务器 在响应头中设置一些特定的字段(如 Access-Control-Allow-Origin
),告诉浏览器:“某个外域的请求是被我允许的,你别拦着”。
一个最简单的 CORS 请求:
-
前端代码(
http://localhost:8080
)正常发起一个 Fetch 请求到http://api.example.com
。 -
服务器(
api.example.com
)在响应头中添加:Access-Control-Allow-Origin: http://localhost:8080 # 或者允许所有域名(慎用) # Access-Control-Allow-Origin: *
-
浏览器看到这个响应头,比对请求的源(
http://localhost:8080
)和Allow-Origin
的值,匹配成功,就会放行,让前端收到响应。
如何实现:主要在服务器端配置。无论是 Node.js (Express)、Java (Spring)、Python (Django/Flask)、Nginx,都可以轻松设置 CORS 响应头。
方案二:反向代理 —— 开发阶段最常用方案
在开发和调试阶段,前端和后端 API 通常在不同端口(如前端 localhost:3000
,后端 localhost:8080
),这也会跨域。
原理:“骗过”浏览器。我们让前端不是直接请求后端的地址,而是请求一个和自己同源的代理服务器(比如就是本地开发服务器)。由这个代理服务器偷偷地去请求真正的后端API,拿到结果后再转发给前端。因为服务器之间通信没有同源策略限制,所以没问题。
实现:
-
Webpack DevServer / Vite: 在
vite.config.js
或webpack.config.js
中配置proxy
。// vite.config.js export default defineConfig({server: {proxy: {'/api': {target: 'http://localhost:8080', // 后端API地址changeOrigin: true,rewrite: (path) => path.replace(/^\/api/, ''),}}} })
-
Nginx: 在生产环境,也常用 Nginx 作为反向代理来处理跨域和负载均衡。