深入浅出聊聊跨域:它到底是个啥,怎么破?


1. 什么是跨域?

先说个故事。

假设你开了家小店,店里有一只看门狗(浏览器的同源策略 )。这只狗的工作很简单:只让本店员工进出,不让陌生人乱窜。但问题来了,你家进货的小哥(前端请求 API)有一天要去隔壁仓库(后端服务器)搬货,结果狗子直接给他拦住了,说:"你不是店里的人,不能去。"

这就是跨域问题的本质------同源策略在作怪。

1.1 这只"狗"是怎么认人的?

浏览器判断"是不是自己人"看的是协议(protocol)、域名(host)、端口号(port) ,只要这三个有任何不同,就会被认定为"外人",触发跨域问题。

URL 1 URL 2 是否同源
http://shop.com http://shop.com ✅ 是同源
http://shop.com https://shop.com ❌ 不同协议
http://shop.com http://api.shop.com ❌ 不同域名
http://shop.com http://shop.com:8080 ❌ 不同端口

所以,哪怕你只是改了个 http 为 https,或者换了个二级域名,浏览器都会大叫:"陌生请求,不要靠近!"


2. 哪些情况会触发跨域?

跨域问题可不仅仅是 fetch 不能用,下面这几种情况,你肯定遇到过:

2.1 AJAX 请求跨域

如果你在 http://shop.com 里用 fetch 请求 http://api.shop.com,会发生什么?

ini 复制代码
fetch("http://api.shop.com/data")
  .then(response => response.json())
  .then(data => console.log(data));

结果: 浏览器直接报 CORS policy error,请求被拦截,凉凉。

2.2 iframe 访问跨域内容

如果你在 shop.com 里嵌套了一个 other.com 的 iframe,然后试图用 JavaScript 访问它的 document:

dart 复制代码
document.querySelector("iframe").contentWindow.document;

结果: DOMException: Permission denied,你被告知"权限不够,禁止访问"。

如果 shop.com 想访问 api.shop.com 的 document.cookie,但 api.shop.com 没有特别配置:

javascript 复制代码
console.log(document.cookie);

结果: 你得到一个空字符串,因为浏览器默认不允许跨域共享 Cookie。


3. 怎么解决跨域问题?

既然这只看门狗这么严格,我们就得想点"妙招"绕过它。以下是几种常见的跨域解决方案,每一种都有各自的适用场景和坑点。


3.1 CORS(跨域资源共享)------ 官方许可的方式

怎么用?

CORS(Cross-Origin Resource Sharing)是服务器端 的解决方案,意思是:让后端主动告诉浏览器"这个请求我允许" 。

后端返回的 HTTP 头需要加上:

makefile 复制代码
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type

如果 Access-Control-Allow-Origin 设为 *,那任何网站都可以访问这个 API。

但如果你要限制访问来源,就需要这样写:

arduino 复制代码
Access-Control-Allow-Origin: https://shop.com

这样,只有 https://shop.com 才能正常请求数据,其他域名访问依然会被拒绝。

适用场景:

  • 前后端分离项目
  • 你能控制 API 服务器的配置

坑点:

  • 预检请求(OPTIONS 请求)可能增加请求耗时
  • Access-Control-Allow-Origin: * 有安全隐患

3.2 JSONP(仅适用于 GET 请求)

怎么用?

JSONP(JSON with Padding)是前端的骚操作 ,通过 <script> 标签加载远程数据:

xml 复制代码
<script src="https://api.shop.com/data?callback=handleResponse"></script>

然后服务器返回这样的数据:

css 复制代码
handleResponse({ message: "Hello, JSONP!" });

浏览器执行后,你就能拿到数据了。

适用场景:

  • 旧的 API
  • 你只需要 GET 请求

坑点:

  • 只能用 GET 请求,POST、PUT、DELETE 全部不行
  • 容易被 XSS 攻击,因为你直接执行了远程 JavaScript 代码

3.3 反向代理(Nginx)------ 最靠谱的方式之一

怎么用?

反向代理的核心思想是:让前端以为它请求的是同源地址,实际由服务器偷偷代理到跨域服务器。

在 Nginx 里,你可以这么配置:

bash 复制代码
location /api/ {
    proxy_pass http://backend.shop.com/;
}

然后,前端请求 http://shop.com/api/data,Nginx 会帮你偷偷请求 http://backend.shop.com/data,绕过浏览器的跨域检查。

适用场景:

  • 生产环境
  • 你有 Nginx 服务器

坑点:

  • 需要服务器支持
  • 可能影响性能

3.4 postMessage(适用于 iframe 跨域通信)

怎么用?

如果你有一个 iframe,而它的内容是跨域的,你可以用 postMessage 进行跨域通信:

javascript 复制代码
window.parent.postMessage("Hello from iframe", "http://shop.com");

// 在父页面里:
window.addEventListener("message", event => {
  if (event.origin === "http://other.com") {
    console.log(event.data);
  }
});

适用场景:

  • iframe 跨域通信
  • 嵌套网页之间的数据传递

坑点:

  • 需要双方配合
  • 必须校验 origin,否则有安全风险

4. 总结

跨域问题是日常开发绕不开的坑,但也有不少的解决方案:

方案 适用场景 优势 限制
CORS API 服务器 简单灵活 需要服务器支持
JSONP 仅 GET 请求 兼容性好 只能 GET,有安全风险
反向代理 生产环境 完全绕过跨域 需要 Nginx 或其他代理
postMessage iframe 通信 适用于嵌套页面 需要双方配合
相关推荐
环境栈笔记几秒前
指纹浏览器安卓怎么用?从运行位置到功能验收,先把三种方案分清
前端·人工智能·后端·自动化
计算机魔术师18 分钟前
Anthropic IPO 招股文件披露近 9000 亿美元隐性债务
前端
Hello.Reader32 分钟前
Three.js / Cesium 卡顿怎么办?把三维渲染搬到 GPU 服务器
服务器·开发语言·javascript
chi113033 分钟前
【无标题】
前端·javascript·python
八月的雨季 最後的冰吻1 小时前
音视频面试--延迟优化
面试·职场和发展·音视频
萝卜兔0081 小时前
PIKACHU_UnsafeFileUpload
javascript·php
ShineWinsu1 小时前
对于Qt:QLabel常见属性的解析
c++·qt·面试·笔试·gui·标签·qlabel
IT_陈寒1 小时前
JavaScript实战技巧总结:深挖数组遍历的性能陷阱与实战解法
前端·人工智能·后端
weixin_307779131 小时前
RAG 级联失效分析——面试中的错误归因艺术
人工智能·python·面试·职场和发展
步行cgn1 小时前
为什么既要 web.xml 又要 springmvc.xml?能不能只配一个?
xml·前端·hive