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


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 ❌ 不同端口

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


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.comiframe,然后试图用 JavaScript 访问它的 document

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

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

如果 shop.com 想访问 api.shop.comdocument.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 通信 适用于嵌套页面 需要双方配合
相关推荐
蒟蒻的工具人1 分钟前
MySQL学习——面试版
学习·mysql·面试
WildBlue2 分钟前
🚀 React Fragment:让代码呼吸的新鲜空气
前端·react.js
遂心_3 分钟前
当 React 遇见数据获取:Ajax 与 Axios 的奇妙冒险 🚀
前端·javascript·react.js
然我4 分钟前
纯函数:相同输入必出相同输出?这才是代码界的 “老实人”
前端·javascript·面试
道里5 分钟前
前端视频封面截取黑帧问题剖析
前端
西瓜树枝8 分钟前
前端必读:HTTP协议核心知识全景图(一)——请求响应、缓存策略
前端
晴殇i10 分钟前
Vue i18n插件:实现Web应用多语言切换的
前端·javascript·vue.js
玲小珑17 分钟前
35+前端工程师的年中失业
前端·年终总结
GDAL18 分钟前
HTML 树结构(DOM)深入讲解教程
前端·html
奈斯啊奈斯_18 分钟前
前端解决浏览器版本延迟问题(webpack)
前端·javascript