跨域基础:浏览器同源策略与解决方案

文章目录

    • 前言
    • 一、同源策略:浏览器的"安全门卫"
      • [1.1 什么是同源?先搞懂"三兄弟"](#1.1 什么是同源?先搞懂"三兄弟")
      • [1.2 浏览器为啥要搞同源策略?安全第一!](#1.2 浏览器为啥要搞同源策略?安全第一!)
    • 二、跨域本质:浏览器拦的,不是服务器
    • 三、2026年主流跨域解决方案(全场景覆盖)
      • [3.1 CORS:现代Web跨域"标准之王"(最推荐)](#3.1 CORS:现代Web跨域"标准之王"(最推荐))
        • [3.1.1 什么是CORS?](#3.1.1 什么是CORS?)
        • [3.1.2 CORS工作流程(极简版)](#3.1.2 CORS工作流程(极简版))
        • [3.1.3 简单请求 vs 预检请求(OPTIONS)](#3.1.3 简单请求 vs 预检请求(OPTIONS))
        • [3.1.4 核心响应头(必须掌握)](#3.1.4 核心响应头(必须掌握))
        • [3.1.5 实战代码(Express+前端)](#3.1.5 实战代码(Express+前端))
      • [3.2 代理服务器:开发/生产"万能钥匙"](#3.2 代理服务器:开发/生产"万能钥匙")
        • [3.2.1 原理(最容易理解)](#3.2.1 原理(最容易理解))
        • [3.2.2 开发环境:Vite/Webpack代理(神器)](#3.2.2 开发环境:Vite/Webpack代理(神器))
        • [3.2.3 生产环境:Nginx反向代理(大厂标准)](#3.2.3 生产环境:Nginx反向代理(大厂标准))
      • [3.3 JSONP:兼容老浏览器的"上古方案"(了解即可)](#3.3 JSONP:兼容老浏览器的"上古方案"(了解即可))
        • [3.3.1 原理](#3.3.1 原理)
        • [3.3.2 实战代码](#3.3.2 实战代码)
      • [3.4 postMessage:iframe/跨窗口通信"专用方案"](#3.4 postMessage:iframe/跨窗口通信"专用方案")
        • [3.4.1 适用场景](#3.4.1 适用场景)
        • [3.4.2 实战代码](#3.4.2 实战代码)
      • [3.5 其他方案(了解)](#3.5 其他方案(了解))
    • 四、方案选型指南(2026年最佳实践)
      • [4.1 开发环境(本地调试)](#4.1 开发环境(本地调试))
      • [4.2 生产环境(自有服务、前后端分离)](#4.2 生产环境(自有服务、前后端分离))
      • [4.3 iframe/多窗口跨域通信](#4.3 iframe/多窗口跨域通信)
      • [4.4 调用第三方接口(不可控)](#4.4 调用第三方接口(不可控))
      • [4.5 绝对禁忌(生产环境)](#4.5 绝对禁忌(生产环境))
    • 五、常见跨域坑与避坑指南(2026最新)
      • [5.1 带Cookie跨域失败(最常见)](#5.1 带Cookie跨域失败(最常见))
      • [5.2 自定义请求头触发OPTIONS预检](#5.2 自定义请求头触发OPTIONS预检)
      • [5.3 端口号被忽略(本地开发)](#5.3 端口号被忽略(本地开发))
      • [5.4 Nginx代理后Cookie丢失](#5.4 Nginx代理后Cookie丢失)
      • [5.5 浏览器缓存导致跨域异常](#5.5 浏览器缓存导致跨域异常)
    • 六、总结:跨域其实很简单

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

前言

老铁们,做前端开发的,谁没被跨域坑过?我敢说,只要你写过AJAX、调过接口、玩过前后端分离,跨域 这两个字绝对是你开发路上的"拦路虎"。控制台那一句经典的 No 'Access-Control-Allow-Origin' header is present on the requested resource,能让多少刚入行的小伙伴直接破防,怀疑人生。

我干开发22年,从早年的ASP、PHP混写,到后来的jQuery时代,再到现在的Vue、React三大框架横行,跨域问题就像狗皮膏药一样,一直跟着Web开发。很多人知其然不知其所以然,只知道CORS、JSONP、Nginx代理这些名词,却不懂浏览器为啥要搞出同源策略,各种方案的本质区别是什么,生产环境该怎么选才最稳妥、最安全。

今天这篇文章,我就用最通俗、最接地气的话,把同源策略的来龙去脉、跨域的本质、以及2026年最新、最实用的解决方案,一次性给你讲透。保证你看完不仅能解决日常开发的跨域坑,面试的时候也能吹得面试官一愣一愣的,直接拿捏。

一、同源策略:浏览器的"安全门卫"

1.1 什么是同源?先搞懂"三兄弟"

要懂跨域,先懂同源。同源(Same-Origin) 是浏览器安全的基石,判断两个URL是否同源,只看三个东西:协议、域名、端口。三者必须完全一致,差一个字母、一个符号、一个数字,都算跨域。

我给你举几个例子,一看就懂:

  • 当前页面:https://www.baidu.com/index.html
    • https://www.baidu.com/api/user ✅ 同源(协议、域名、端口全一样)
    • http://www.baidu.com/api/user ❌ 不同源(协议不同:https vs http)
    • https://map.baidu.com/api ❌ 不同源(子域名不同:www vs map)
    • https://www.baidu.com:8080/api ❌ 不同源(端口不同:默认443 vs 8080)
    • https://baidu.com/api ❌ 不同源(域名不同:www.baidu.com vs baidu.com

简单记:协议、域名、端口,一个都不能少。少一个、变一个,浏览器就不认你是自己人。

1.2 浏览器为啥要搞同源策略?安全第一!

很多新手吐槽:同源策略太烦了,限制这限制那,直接关掉不香吗?

大错特错! 同源策略是浏览器的"安全门卫",没有它,你上网就等于裸奔。

我给你打个比方:

你登录了银行网站(bank.com),Cookie里存了登录态。这时候你不小心点开一个恶意网站(hacker.com)。如果没有同源策略,恶意网站的JS就能直接读取你银行网站的Cookie、获取你的账户信息、甚至偷偷发起转账请求------你的钱瞬间就没了。

同源策略的核心目的,就是隔离不同源的资源,防止恶意网站窃取数据、伪造请求、篡改DOM。它主要限制三件事:

  1. AJAX/Fetch请求限制:不同源的接口,直接请求会被浏览器拦截,控制台报错
  2. DOM访问限制:不同源的iframe/窗口,不能互相读取DOM、调用方法
  3. 存储访问限制:不同源不能读取对方的Cookie、LocalStorage、IndexedDB

一句话总结:同源策略是浏览器的安全底线,跨域问题是安全与开发便利的矛盾产物。我们要做的,不是打破安全,而是在安全框架内,找到合法合规的"通行证"。

二、跨域本质:浏览器拦的,不是服务器

这里有个超级关键的点,90%的新手都搞混:跨域拦截,是浏览器干的,跟服务器没关系!

我再强调一遍:

  • 服务器收到跨域请求,正常处理、正常返回数据
  • 浏览器拿到服务器返回的结果,检查是否符合同源策略
  • 不符合,浏览器直接把数据扔掉,抛给你一个跨域错误
  • 服务器全程不知道自己的响应被浏览器丢了

这就好比:

你(浏览器)去快递站(服务器)取快递(数据)。快递站不管你是谁,把包裹给你了。但你回家路上,被小区保安(同源策略)拦住了:"这个包裹不是你家(同源)的,不能带进小区!" 于是你只能把包裹扔了,还跟主人(前端代码)说:"取不到,被拦了!"

所以:

  • 服务器没毛病,响应正常
  • 问题出在浏览器的安全校验
  • 解决跨域,本质就是让浏览器知道:这个跨域请求是合法的、被允许的

三、2026年主流跨域解决方案(全场景覆盖)

3.1 CORS:现代Web跨域"标准之王"(最推荐)

3.1.1 什么是CORS?

CORS(Cross-Origin Resource Sharing,跨域资源共享),是W3C官方标准,2026年开发首选、最规范、最安全的跨域方案

原理一句话:服务器通过HTTP响应头,告诉浏览器:"这个来源我允许访问,放行!"

3.1.2 CORS工作流程(极简版)
  1. 浏览器发起跨域请求,自动在请求头加 Origin: 当前域名
  2. 服务器收到请求,检查Origin是否在白名单
  3. 允许:返回 Access-Control-Allow-Origin: 允许的域名
  4. 浏览器检查响应头,匹配成功:把数据给前端
  5. 不允许:浏览器拦截,抛跨域错误
3.1.3 简单请求 vs 预检请求(OPTIONS)

CORS分两种请求,面试必考:

① 简单请求(满足两个条件)

  • 方法:GET/HEAD/POST
  • 请求头只有:Accept、Accept-Language、Content-Language、Content-Type(仅限application/x-www-form-urlencoded、multipart/form-data、text/plain)

特点:直接发请求,服务器返回CORS头即可。

② 非简单请求 (PUT/DELETE/自定义头/Content-Type:application/json)

特点:浏览器先发OPTIONS预检请求 ,问服务器:"我要发XX方法、带XX头,你允许吗?"

服务器同意:返回204,浏览器再发真实请求

服务器拒绝:直接拦截,真实请求不发

3.1.4 核心响应头(必须掌握)
http 复制代码
# 允许的源(生产别用*,要指定具体域名)
Access-Control-Allow-Origin: https://www.your-frontend.com
# 允许的请求方法
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
# 允许的请求头
Access-Control-Allow-Headers: Content-Type,Authorization,Token
# 是否允许携带Cookie(true时,Allow-Origin不能用*)
Access-Control-Allow-Credentials: true
# 预检缓存时间(秒),减少OPTIONS请求
Access-Control-Max-Age: 86400
3.1.5 实战代码(Express+前端)

后端(Express)

javascript 复制代码
// 全局CORS中间件(生产建议用cors库)
app.use((req, res, next) => {
  // 允许的前端域名
  const allowOrigin = ['https://www.a.com','https://www.b.com']
  const origin = req.headers.origin
  if(allowOrigin.includes(origin)){
    res.header('Access-Control-Allow-Origin', origin)
  }
  res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS')
  res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization')
  res.header('Access-Control-Allow-Credentials', 'true')
  // 处理OPTIONS预检
  if(req.method === 'OPTIONS'){
    return res.sendStatus(204)
  }
  next()
})

前端(带Cookie请求)

javascript 复制代码
// fetch
fetch('https://api.your-backend.com/user', {
  method: 'GET',
  credentials: 'include' // 关键:携带Cookie
})

// axios
axios.get('https://api.your-backend.com/user', {
  withCredentials: true // 关键
})

优点 :标准、支持所有请求、安全、可控
缺点 :必须后端配合配置
适用:前后端分离、自有服务、生产环境首选

3.2 代理服务器:开发/生产"万能钥匙"

3.2.1 原理(最容易理解)

同源策略只限制浏览器,服务器之间通信没有跨域

代理方案:

  1. 前端 → 请求同源代理地址 (如/api/xxx
  2. 代理服务器(本地/Vite/Nginx)→ 转发到真实后端
  3. 代理服务器拿到响应 → 返回给前端
  4. 浏览器以为是同源请求,直接放行
3.2.2 开发环境:Vite/Webpack代理(神器)

Vite配置(2026最主流)

javascript 复制代码
// vite.config.js
export default {
  server: {
    proxy: {
      '/api': {
        target: 'https://api.your-backend.com', // 真实后端
        changeOrigin: true, // 改Host头
        rewrite: (path) => path.replace(/^\/api/, '') // 路径重写(可选)
      }
    }
  }
}

前端直接请求 /api/user,浏览器不跨域,开发爽到爆。

3.2.3 生产环境:Nginx反向代理(大厂标准)

线上项目,几乎都用Nginx统一入口,彻底消灭跨域。

Nginx配置

nginx 复制代码
server {
  listen 80;
  server_name www.your-site.com;

  # 前端静态文件
  location / {
    root /usr/share/nginx/html;
    index index.html;
  }

  # 接口代理到后端
  location /api {
    proxy_pass https://api.your-backend.com; # 真实后端
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

用户访问 www.your-site.com/api/user,Nginx转发到后端,浏览器全程以为是同源。

优点 :前端无感知、彻底解决跨域、安全、可加限流/负载均衡
缺点 :需配置代理服务器
适用:开发环境调试、生产环境统一入口

3.3 JSONP:兼容老浏览器的"上古方案"(了解即可)

3.3.1 原理

利用 <script> 标签不受同源策略限制的特性:

  1. 前端动态创建 <script src="https://api.com?callback=handleData">
  2. 服务器返回:handleData({ name:"张三" })(JS函数调用)
  3. 浏览器加载执行,前端拿到数据
3.3.2 实战代码
javascript 复制代码
// 前端
function handleData(data){
  console.log('拿到数据:', data)
}
const script = document.createElement('script')
script.src = 'https://api.your-backend.com/data?callback=handleData'
document.body.appendChild(script)

优点 :兼容IE6-8(2026几乎不用)
缺点 :仅支持GET、不安全、无法发POST/PUT、无法处理错误
适用:极老系统、第三方不支持CORS的接口(极少)

3.4 postMessage:iframe/跨窗口通信"专用方案"

3.4.1 适用场景

页面嵌套iframe、多窗口(window.open)之间跨域通信。

3.4.2 实战代码

父页面(a.com

javascript 复制代码
// 向子iframe发消息
const iframe = document.getElementById('child-iframe')
iframe.contentWindow.postMessage(
  { type:'hello', data:'来自父页面' },
  'https://b.com' // 必须指定子页面域名,安全!
)

// 监听子页面返回
window.addEventListener('message', (e) => {
  // 安全校验:必须验证来源
  if(e.origin !== 'https://b.com') return
  console.log('子页面消息:', e.data)
})

子iframe页面(b.com

javascript 复制代码
// 监听父页面消息
window.addEventListener('message', (e) => {
  if(e.origin !== 'https://a.com') return
  console.log('父页面消息:', e.data)
  // 回复消息
  e.source.postMessage({ type:'reply', data:'收到了' }, e.origin)
})

安全铁律

  • 生产环境绝对不能用 targetOrigin: *
  • 必须校验 event.origin,只信任指定域名

优点 :HTML5标准、安全、双向通信
缺点 :仅适用于窗口/iframe场景
适用:iframe嵌套、多窗口跨域通信

3.5 其他方案(了解)

3.5.1 document.domain:主域相同子域跨域

适用:a.xxx.comb.xxx.com

javascript 复制代码
// 两个页面都设置
document.domain = 'xxx.com'

即可互相访问DOM/Cookie。

3.5.2 WebSocket:实时通信无跨域

WebSocket协议不受同源策略限制,可直接跨域通信。

javascript 复制代码
const ws = new WebSocket('wss://api.your-backend.com/ws')

适合聊天室、直播、实时数据推送。

3.5.3 window.name/location.hash:过时方案

兼容性差、不安全、功能有限,2026年基本淘汰,了解即可。

四、方案选型指南(2026年最佳实践)

讲了这么多方案,很多人懵了:我到底该用哪个?

直接给你2026年最实用、最稳妥的选型结论,照着选不出错:

4.1 开发环境(本地调试)

首选:Vite/Webpack 代理

理由:前端一键配置、无需后端配合、开发效率拉满、零成本解决跨域。

4.2 生产环境(自有服务、前后端分离)

首选:CORS(后端配置)

理由:W3C标准、安全可控、支持所有请求、性能最好、无中间层损耗。

备选:Nginx反向代理

理由:后端不方便改配置、需要统一入口、隐藏后端地址、加负载均衡/限流。

4.3 iframe/多窗口跨域通信

唯一选择:postMessage

理由:HTML5标准、安全、官方推荐、双向通信。

4.4 调用第三方接口(不可控)

  • 支持CORS:直接用CORS
  • 不支持CORS:自己服务器搭一层代理(前端→你的代理→第三方接口),绝对别用JSONP。

4.5 绝对禁忌(生产环境)

  1. 禁止CORS用 Access-Control-Allow-Origin: *(带Cookie时完全失效、不安全)
  2. 禁止postMessage用 targetOrigin: *(极易被劫持)
  3. 禁止生产环境用JSONP(仅GET、不安全)
  4. 禁止随意关闭浏览器同源策略(本地调试偶尔用,线上绝对不行)

五、常见跨域坑与避坑指南(2026最新)

5.1 带Cookie跨域失败(最常见)

原因三要素

  1. 后端 Access-Control-Allow-Credentials: true
  2. 后端 Access-Control-Allow-Origin 必须指定具体域名 ,不能用*
  3. 前端请求必须带 credentials: include(fetch)或 withCredentials: true(axios)

5.2 自定义请求头触发OPTIONS预检

加了Token/Authorization等自定义头,浏览器自动发OPTIONS。
解决 :后端配置 Access-Control-Allow-Headers 包含自定义头,并处理OPTIONS请求。

5.3 端口号被忽略(本地开发)

本地:localhost:3000 前端 → localhost:8080 后端
端口不同算跨域,必须用代理或CORS。

5.4 Nginx代理后Cookie丢失

解决:Nginx加配置

nginx 复制代码
proxy_cookie_domain backend.com your-site.com;
proxy_set_header Cookie $http_cookie;

5.5 浏览器缓存导致跨域异常

解决 :清浏览器缓存、禁用缓存、加 Cache-Control: no-cache

六、总结:跨域其实很简单

最后,用几句话把全文浓缩,方便你记忆:

  1. 同源 = 协议+域名+端口完全相同,浏览器安全基石
  2. 跨域拦截是浏览器干的,服务器正常返回,浏览器扔结果
  3. 2026首选方案:开发用代理、生产用CORS、iframe用postMessage
  4. 安全第一 :生产别用*、校验origin、不用JSONP
  5. 跨域不是难题,懂原理、选对方案、规范配置,轻松搞定

跨域是前端开发的基础中的基础,也是面试高频考点。把这篇文章吃透,日常开发的跨域坑基本都能踩平,面试也能从容应对。

Web开发日新月异,但同源策略和跨域的核心原理永远不变。掌握本质,才能以不变应万变。

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

相关推荐
醇氧2 小时前
用 CC Switch (cc-sw) 配置 Claude Code 接入 阿里云百炼 (Dashscope)
人工智能·学习·阿里云·ai·云计算
树獭非懒2 小时前
Harness Engineering:为什么你的 AI 不好用,其实不是模型的问题
人工智能·程序员·llm
晨欣2 小时前
LLM 推理性能指标全解:TTFT、TBT、Output Speed、Throughput、SLO 怎么用(GPT-5.4-high生成)
人工智能·gpt·llm
阿洛学长2 小时前
2026年最佳AI提示词合集:ChatGPT、Claude、Gemini 提示词大全
人工智能·ai·chatgpt·ai作画
寂寞旅行2 小时前
模型蒸馏: 小模型也有“大用“
人工智能·embedding
东离与糖宝2 小时前
Python 包结构基础:init.py 作用
人工智能
财迅通Ai10 小时前
商业航天概念领涨A股,航天ETF华安(159267.SZ)收盘上涨1.2%
大数据·人工智能·区块链·中国卫星·航天电子
齐齐大魔王10 小时前
智能语音技术(八)
人工智能·语音识别
许彰午10 小时前
零成本搭建RAG智能客服:Ollama + Milvus + DeepSeek全程实战
人工智能·语音识别·llama·milvus