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


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 通信 适用于嵌套页面 需要双方配合
相关推荐
小离a_a36 分钟前
使用原生css实现word目录样式,标题后面的...动态长度并始终在标题后方(生成点线)
前端·css
郭优秀的笔记1 小时前
抽奖程序web程序
前端·css·css3
布兰妮甜1 小时前
CSS Houdini 与 React 19 调度器:打造极致流畅的网页体验
前端·css·react.js·houdini
小小愿望2 小时前
ECharts 实战技巧:揭秘 X 轴末项标签 “莫名加粗” 之谜及破解之道
前端·echarts
小小愿望2 小时前
移动端浏览器中设置 100vh 却出现滚动条?
前端·javascript·css
fail_to_code2 小时前
请不要再只会回答宏任务和微任务了
前端
摸着石头过河的石头2 小时前
taro3.x-4.x路由拦截如何破?
前端·taro
lpfasd1232 小时前
开发Chrome/Edge插件基本流程
前端·chrome·edge
练习前端两年半3 小时前
🚀 Vue3 源码深度解析:Diff算法的五步优化策略与最长递增子序列的巧妙应用
前端·vue.js
烛阴3 小时前
TypeScript 接口入门:定义代码的契约与形态
前端·javascript·typescript