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


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 通信 适用于嵌套页面 需要双方配合
相关推荐
设计师小聂!4 分钟前
vue3 - 自定义hook
开发语言·javascript·ecmascript
伍哥的传说5 分钟前
daisyUI 扩展之 pin input 组件开发,极致pin码输入框
前端·javascript·react.js·交互
云小遥33 分钟前
Cornerstone3D 2.x升级调研
前端·数据可视化
李明卫杭州39 分钟前
浅谈JavaScript中Blob对象
前端·javascript
springfe010139 分钟前
Cesium 3D地图 图元 圆柱 图片实现
前端·cesium
meng半颗糖41 分钟前
vue3 双容器自动扩展布局 根据 内容的多少 动态定义宽度
前端·javascript·css·vue.js·elementui·vue3
yt9483243 分钟前
jquery和CSS3圆形倒计时特效
前端·css3·jquery
teeeeeeemo44 分钟前
CSS3 动画基础与技巧
前端·css·笔记·css3
年纪轻轻就扛不住1 小时前
CSS3 渐变效果
前端·css·css3
Aisanyi1 小时前
【鸿蒙开发】使用HMRouter路由的使用
前端·harmonyos