深入讨论前端开发中的跨域问题🤔

前言

前后端分离已成为现代web开发中的主流模式,前端页面通过JavaScript向后端API发起请求获取数据、访问资源等等。但是,访问资源、请求数据能够随意访问吗?或者说,随意访问后端资源会出现哪些问题?这就涉及到了现在前后端开发中一个极为重要的问题------------跨域问题。

一、跨域问题是啥?

1.1 定义

跨域问题就是指:浏览器出于安全考虑,阻止一个网站的 JavaScript 向另一个网站发送请求并获取数据。而要限制请求对数据的访问,则是依靠一个重要策略------同源策略(Same-Origin Policy)

1.2 啥是"同源"?

首先得知道"源"是什么。这里的"源"=协议+域名+端口号,那么,只要两个请求在这三项里面有一项不同,那就可以视为非同源请求 例如:

  • http://example.com:80http://example.com:80 ------ 同源
  • http://example.com:80https://example.com:80 ------ 不同源(协议不同)
  • http://example.com:80http://api.example.com:80 ------ 不同源(主域不同)
  • http://example.com:80http://example.com:8080 ------ 不同源(端口不同)

为什么需要同源策略?

Web 的本质是开放,任何网站都可以被用户访问,如果不加以限制,A 网站的脚本就可以访问 B 网站的用户信息、发起恶意请求,造成数据泄露、权限滥用、CSRF 攻击 等一系列问题。因此,浏览器强制实施了同源策略(SOP) ,阻止不同源之间的资源访问和交互。

1.3 什么行为会被浏览器拦截?

以下行为如果发生跨域,会被浏览器拦截或受限:

  • 通过 JavaScript 的 XMLHttpRequest / fetch 请求外部 API
  • 读取非同源 iframe 的内容
  • 操作 window.open() 打开的非同源页面
  • 设置或读取非同源 Cookie / Storage 数据

注意:标签加载资源(如 <img>, <script>, <link>)不会受到跨域限制,但这也可能带来潜在的安全隐患(例如CSRF、XSS)。


第二章:常见的跨域场景

2.1 本地开发中前后端分离

本地开发时,前端常运行在:

arduino 复制代码
arduino
复制编辑
http://localhost:3000

而后端接口则部署在:

bash 复制代码
bash
复制编辑
http://localhost:5000 或 http://api.example.com

前端通过 fetch('http://api.example.com/data') 请求数据时,由于端口或域名不同,属于跨域请求,浏览器将其视为潜在安全风险,可能拦截或限制请求行为。

2.2 多服务架构中的子域交互

例如:

  • 前端页面部署在 https://www.example.com
  • 图片服务部署在 https://img.example.com
  • 用户服务部署在 https://user.example.com

它们虽然属于同一主域(example.com),但由于子域不同,依旧会被视为跨域。

2.3 第三方服务嵌入

如嵌入社交媒体组件、支付接口、广告投放脚本等,也属于跨域交互。


第三章:浏览器的跨域拦截机制详解

3.1 简单请求(Simple Request)

满足以下条件的请求被认为是"简单请求",浏览器会直接发出请求:

  • 请求方法是:GET, POST, 或 HEAD
  • 请求头为浏览器自动添加的简单头部 (如 Accept, Content-Typeapplication/x-www-form-urlencoded, multipart/form-data, 或 text/plain
  • 没有使用自定义头部、Body 结构等复杂内容

浏览器行为:直接发出请求,但只能在目标服务允许的情况下读取响应。

3.2 预检请求(Preflight Request)

当请求不满足简单请求的条件,浏览器会先发送一个 OPTIONS 请求作为"预检",询问服务器是否允许真正的请求。

示例:

makefile 复制代码
http
复制编辑
OPTIONS /data HTTP/1.1
Origin: http://localhost:3000
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header

服务器需要响应:

makefile 复制代码
http
复制编辑
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 86400

第四章:常用跨域解决方案

4.1 CORS(跨域资源共享)

最官方、最推荐的解决方案。需要服务器设置响应头来声明"我允许哪些来源的访问"。

服务端设置(Node.js + Express 示例):
javascript 复制代码
js
复制编辑
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  next();
});

如果使用框架,如Spring Boot、Django、ASP.NET等,也有对应的CORS配置。

4.2 开发代理(Dev Proxy)

前端构建工具如Webpack、Vite、Create React App 提供开发服务器代理配置,把请求转发给后端,从而绕过跨域限制。

Vite 配置示例:
css 复制代码
js
复制编辑
server: {
  proxy: {
    '/api': {
      target: 'http://localhost:5000',
      changeOrigin: true,
      rewrite: path => path.replace(/^/api/, '')
    }
  }
}

前端访问 /api/user 实际被代理为 http://localhost:5000/user

4.3 JSONP(已过时,仅支持GET)

通过 <script> 标签的跨域能力,动态创建脚本标签请求数据,并执行回调。

不推荐现代项目使用,原因如下:

  • 仅支持 GET 请求
  • 存在XSS注入风险
  • 数据格式不规范,难以调试

4.4 Nginx 反向代理

将 Nginx 设置为前后端统一入口,请求由 Nginx 中转,实现跨域绕过。

bash 复制代码
nginx
复制编辑
location /api/ {
  proxy_pass http://backend.example.com/;
  proxy_set_header Host $host;
}

4.5 iframe + postMessage

用于跨域嵌套页面之间的通信:

  • 父页面创建 iframe 嵌套其他域名
  • 子页面通过 window.parent.postMessage() 通知父页面
  • 父页面用 window.addEventListener('message', handler) 接收消息

适用于支付、嵌套服务等需要跨域通信的特殊场景。


第五章:跨域安全性分析

5.1 CORS 和 CSRF 的关系

CORS 本身不是一种防御机制,而是限制访问者获取跨域数据的机制 。如果服务器没有设置合理的 Access-Control-Allow-OriginAccess-Control-Allow-Credentials,容易被用于CSRF攻击。

应对方法:

  • 服务端设置 SameSite Cookie 属性为 StrictLax
  • 对关键接口使用 CSRF Token 双重校验机制
  • 限制 Access-Control-Allow-Origin 不使用通配符(*

5.2 JSONP 的风险

JSONP 会将返回的数据作为 JavaScript 执行,如果攻击者伪造 callback 参数,可能导致恶意代码注入。

5.3 反向代理中的隐藏风险

如果代理规则配置错误,可能暴露不该访问的接口,例如:

  • 管理员接口被前端访问
  • 未登录用户访问需要认证的数据

第六章:实际开发中的最佳实践

6.1 本地开发时优先使用代理

  • 使用前端工具配置代理
  • 避免频繁修改后端 CORS 配置
  • 适配本地与生产部署的差异

6.2 生产环境必须由服务端控制跨域

  • 严格限定允许的域名
  • 不使用 * 通配符与 Cookie 共用
  • 对敏感接口启用身份校验机制(如JWT、Session)

6.3 对iframe通信进行来源校验

javascript 复制代码
js
复制编辑
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://trusted.com') return;
  // 安全处理
});

第七章:前端框架与跨域

React

  • fetch 默认不会携带 Cookie,需要设置 credentials: 'include'
  • 使用 CRA(Create React App)时可以配置 setupProxy.js

Vue

  • Vue CLI 提供 devServer.proxy 配置
  • Axios 默认不会携带 Cookie
ini 复制代码
js
复制编辑
axios.defaults.withCredentials = true;

Angular

  • 使用 HttpClient 时可配置 withCredentials 选项

第八章:未来的发展与标准化趋势

随着浏览器对安全的关注度不断提升,跨域机制也在不断演化:

  • Fetch APIService Worker 支持更灵活的跨域请求控制
  • COOP / COEP / CORP 安全头提升隔离性
  • WebAssembly、WebGPU 等新技术也可能引入新的跨域安全模型

结语

跨域是前端开发中极其重要且不可忽视的问题。它并不是一种"错误",而是浏览器提供的安全保护机制。开发者应理解其原理,掌握常见场景与解决方案,在满足业务需求的同时保障系统安全。

相关推荐
anyup36 分钟前
🔥牛逼!3分钟生成 5 套主题,还能一键切换暗黑模式!
前端·前端框架·uni-app
正在走向自律40 分钟前
企业微信消息推送全链路实战:Java后端与Vue前端集成指南
前端·vue.js·企业微信·企业微信消息推送·官方企业微信
_一两风41 分钟前
《从一道“诡异”输出题,彻底搞懂 JavaScript 的作用域与执行上下文》
前端·ecmascript 6
lcc18744 分钟前
Vue3 CompositionAPI的优势
前端·vue.js
五号厂房1 小时前
聊一聊前端下载文件N种方式
前端
code_Bo1 小时前
使用micro-app 多层嵌套的问题
前端·javascript·架构
小灰1 小时前
VS Code 插件 Webview 热更新配置
前端·javascript
进击的明明1 小时前
前端监控与前端兜底:那些我们平常没注意,但真正决定用户体验的“小机关”
前端·面试
前端老宋Running1 小时前
我只改了个头像,为什么整个后台系统都闪了一下?
前端·react.js·面试