前端跨域全解:原理+9种方案+实战代码,一篇吃透

43 阅读5分钟

前端跨域全解:原理+9种方案+实战代码,一篇吃透

跨域是前端面试高频考点,也是开发必踩坑。本文从同源策略讲起,拆解跨域本质,详解9种主流跨域方案,附可直接复制的实战代码,帮你一次吃透跨域。

一、先搞懂:什么是同源策略?

跨域的根源,是浏览器的同源策略(Same-Origin Policy)——这是浏览器最核心的安全机制,用于隔离不同源的资源,防止恶意网站窃取数据。

同源判定3要素(必须完全一致)

  • 协议:http/https
  • 域名:主域名/子域名(www.xxx.com ≠ api.xxx.com)
  • 端口:8080≠3000

举个例子 前端:http://localhost:5173 后端:http://localhost:3000 → 端口不同,跨域 前端:https://www.juejin.cn 前端:http://www.juejin.cn → 协议不同,跨域

二、跨域从哪来?浏览器的安全红线

  • 跨域只存在于浏览器,服务器之间请求无跨域限制
  • 浏览器会拦截不同源的 Ajax/Fetch 请求,但允许 <script>/<img>/<link> 等标签跨域加载资源

三、同源策略到底限制了什么?

  1. 无法读取不同源的 Cookie、LocalStorage、IndexedDB
  2. 无法获取不同源的 DOM 元素
  3. 无法发送不同源的 Ajax/Fetch 请求(核心痛点)

四、9种跨域解决方案,原理+代码全解析

1. JSONP:最古老的跨域方案(兼容IE6+)

原理:利用 <script> 标签无跨域限制,通过回调函数获取数据 优点:兼容性拉满;缺点:仅支持GET,不安全,不支持复杂请求

// 前端代码
function handleData(res) {
  console.log("JSONP返回数据:", res);
}
const script = document.createElement("script");
script.src = "http://localhost:3000/api/jsonp?callback=handleData";
document.body.appendChild(script);

// 后端Node.js返回
app.get("/api/jsonp", (req, res) => {
  const callback = req.query.callback;
  const data = { name: "掘金", msg: "JSONP跨域成功" };
  res.send(`${callback}(${JSON.stringify(data)})`);
});

2. CORS:现代前端首选标准方案

全称:Cross-Origin Resource Sharing(跨域资源共享) 原理:后端设置响应头,明确允许指定源访问,浏览器验证通过后放行 分类:简单请求、预检请求(OPTIONS)

优点:支持所有请求方式,安全规范;缺点:依赖后端配置

// 后端Node.js + Express 配置CORS
const express = require("express");
const app = express();
// 允许所有源(开发用)
app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type");
  next();
});
// 带Cookie的CORS
// res.setHeader("Access-Control-Allow-Credentials", "true");
// res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");

3. 前端本地代理:开发环境神器(Webpack/Vite)

原理:本地启动代理服务器,转发请求绕过浏览器跨域限制 优点:前端无感知,开发效率高;缺点:仅适用于开发环境

// Vite 代理配置 vite.config.js
export default {
  server: {
    proxy: {
      "/api": {
        target: "http://localhost:3000", // 后端地址
        changeOrigin: true, // 修改Origin为目标源
        rewrite: (path) => path.replace(/^\/api/, ""),
      },
    },
  },
};

// Webpack 代理配置 webpack.config.js
devServer: {
  proxy: {
    "/api": {
      target: "http://localhost:3000",
      changeOrigin: true,
    },
  },
}

4. Nginx反向代理:生产环境首选

原理:Nginx作为网关,转发前端请求到后端,浏览器只认Nginx为同源 优点:高性能,无侵入,适合生产;缺点:需运维配置

# Nginx 配置
server {
  listen 80;
  server_name localhost;
  location /api/ {
    proxy_pass http://localhost:3000/; # 转发到后端
    add_header Access-Control-Allow-Origin *;
  }
}

5. postMessage:iframe/跨窗口通信神器

原理:HTML5标准API,实现窗口/iframe之间安全通信 适用场景:iframe嵌套、多窗口数据传递

// 父页面发送消息
const iframe = document.getElementById("child-iframe");
iframe.contentWindow.postMessage("来自父页面的消息", "http://localhost:3000");

// 子页面接收消息
window.addEventListener("message", (e) => {
  if (e.origin !== "http://localhost:5173") return; // 验证源安全
  console.log("子页面收到:", e.data);
});

6. WebSocket:全双工无跨域

原理:WebSocket协议不受同源策略限制,实现实时通信 适用场景:聊天室、直播、实时数据推送

// 前端WebSocket
const ws = new WebSocket("ws://localhost:3000/ws");
ws.onopen = () => ws.send("前端连接成功");
ws.onmessage = (e) => console.log("收到服务端消息:", e.data);

7. document.domain:主域相同的子域跨域

原理:强制设置相同主域名,实现子域间通信 适用场景:a.xxx.com 与 b.xxx.com 跨域

// 两个页面都设置
document.domain = "xxx.com";

8. window.name:轻量iframe跨域

原理:iframe的name属性跨域不重置,用于临时存储数据 优点:简单;缺点:仅iframe场景,兼容性一般

9. location.hash:哈希传值跨域

原理:通过URL哈希值传递数据,监听hashchange事件 优点:无依赖;缺点:数据量小,不安全,已淘汰

五、方案对比:怎么选才对?

方案支持请求兼容性生产推荐适用场景
CORS全部现代浏览器✅✅✅绝大多数前后端分离项目
本地代理全部全兼容❌(仅开发)本地开发调试
Nginx代理全部全兼容✅✅✅生产环境部署
JSONPGETIE6+老旧浏览器兼容
postMessage通信现代浏览器iframe/跨窗口
WebSocket全双工现代浏览器实时通信

六、实战最佳实践

  1. 开发环境:用Webpack/Vite本地代理,零配置快速开发
  2. 生产环境:后端CORS + Nginx反向代理,安全高效
  3. 特殊场景:iframe用postMessage,实时通信用WebSocket
  4. 安全提醒:CORS不要用*,指定具体域名;带Cookie必须配置Access-Control-Allow-Credentials

七、总结

跨域的核心是浏览器同源策略,解决思路只有两种:

  1. 让浏览器认为请求是同源的(代理、Nginx)
  2. 让后端明确授权允许跨域(CORS)

现代前端开发,CORS + 代理 + Nginx 已覆盖99%场景,JSONP等历史方案仅做兼容了解即可。

本文已覆盖面试与开发全场景,建议收藏备用~ 有问题欢迎评论区交流!


标签:#前端 #跨域 #CORS #同源策略 #面试

文章已按掘金风格完成,包含原理、代码、选型、最佳实践,可直接发布。需要我帮你精简成面试版补充Vue/React实战示例调整排版吗?