logo

Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll

React 中的 CORS:它是什么、为什么重要,以及如何启用

04/09/2025, by Ivan

在 React 中理解 CORS

CORS 长期以来一直让开发者(尤其是入门者)感到困惑——甚至沮丧。这个概念并不直观,特别是当你使用 React、Angular 或 Vue 等框架构建单页应用(SPA)并尝试与第三方 API 交互时。

在本指南中,我会从零开始帮助你理解 CORS。我们将搭建一个简单的 React 应用和一个 Express 服务器,来演示究竟是什么触发了 CORS 错误以及它们为何发生。更重要的是,我会带你逐步了解多种解决方法——既包含通用思路,也包含在 React 环境中的具体做法。


什么是 CORS?

CORS(跨域资源共享,Cross-Origin Resource Sharing)是一种协议,用于规范 Web 应用如何从不同来源(origin)的服务器请求资源。就像 HTTPS 规定了安全通信的规则一样,CORS 规定了跨域请求的规则。

现代 Web 应用通常被拆分为两个关键部分:客户端(运行在你的浏览器中的前端)和服务器(通常是一个 API 或后端服务)。客户端向服务器发送请求——例如获取数据——而服务器返回响应。当这两部分运行在不同的域名、端口或协议上时,CORS 就会介入。

CORS localhost
请求到 localhost。

为何这种架构如此常见

这种前后端分离、分别开发和部署的解耦架构正越来越流行。一个主要优势是灵活性:你的后端可以同时服务多种客户端,包括 Web 应用、桌面界面、移动应用,甚至是 IoT 设备。每个客户端都能消费同一套 API,而不与展示层强耦合。


同源策略与跨域请求

由于客户端和服务器是两个独立应用,它们通常托管在不同的域名、端口或协议上。这意味着即使是你的自有前端在访问你的自有后端时,浏览器也可能将该请求视为跨域

当你使用第三方服务(如认证、分析、支付网关等)时,这种情况更为常见。在这些场景中,你的前端需要通过 HTTP 请求与不同的源进行交互。

问题在于:现代浏览器强制执行一种名为同源策略(Same-Origin Policy)的安全机制,用来限制运行在一个源上的脚本如何与另一个源的资源交互。这正是CORS发挥作用的地方——它是一种安全地启用跨域请求的机制。

CORS settings
来自同一源的服务器到客户端的响应

为什么浏览器会阻止跨域请求

当你的 Web 应用尝试从不同的源(如不同的域名、端口或协议)请求资源时,浏览器会执行名为同源策略(SOP)的安全机制。该策略旨在防止潜在的恶意网站在未经许可的情况下访问另一个源上的敏感数据。

从历史上看,这极大地提升了 Web 的安全性。例如,运行在 xyz.com 上的脚本无法悄悄获取 abcbank.com 的个人数据,从而保护用户免受跨站攻击。但是,同源策略也会阻止一些合法场景——比如你的 React 应用运行在 localhost:3000,尝试从运行在 localhost:8080 的 API 或某个外部服务获取数据时。


引入 CORS:SOP 限制的解决之道

这就是 CORS跨域资源共享)登场的地方。

CORS 是一种在受控条件下放宽同源策略的协议。它允许服务器通过特定的 HTTP 头部来表明某些跨域请求是安全且被允许的。

因此,当你的客户端应用向不同源发出请求时,服务器可以在响应中返回一组特殊的 CORS 头。它们就像一张“许可条”,告诉浏览器:“这个跨域请求是允许的。” 于是浏览器不再拦截该响应,资源即可被成功共享。

Get response with CORS
启用 CORS 后的客户端—服务器请求与响应。

启用 CORS 后会发生什么?

一旦浏览器在服务器响应中检测到 CORS 头,就会允许你的应用访问该数据——即便请求的来源与目标不同。这就是 CORS 的精髓:在不同源之间进行受控的资源访问。

现在你已经理解了 CORS 是什么以及为什么需要它,我们来通过一个上手示例看看它的实际效果。如果你想更深入地学习,也可以查看这篇深入的 CORS 指南以获取更多细节。


🛠️ 第一步:创建带 API 端点的 Express 服务器

为了演示 CORS 如何工作,我们需要:

  • 一个发起 HTTP 请求的客户端(用 React 构建)

  • 一个暴露 API 端点、用于响应这些请求的服务器(用 Express 构建)

⚠️ 要触发真实的 CORS 场景,客户端和服务器必须运行在不同的源上——例如不同的端口,如 localhost:3000localhost:8080


🧱 搭建服务器

我们先创建一个基础的 Express 服务器。

  1. 创建项目文件夹

mkdir cors-server && cd cors-server
  1. 初始化一个新的 Node.js 项目

npm init -y

这会创建一个带默认值的 package.json 文件。

  1. 安装 Express

npm install express
  1. 创建应用入口文件

在项目根目录创建名为 app.js 的文件,并加入如下代码:

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Welcome to CORS server 😁');
});

app.get('/cors', (req, res) => {
  res.send('This has CORS enabled 🎈');
});

app.listen(8080, () => {
  console.log('Listening on port 8080');
});

这是一个包含两个端点的最小化 Express 服务器:

  • / 返回欢迎消息。

  • /cors 模拟一个你会从 React 应用进行获取的资源端点。

  1. 运行服务器

node app

启动后,访问 http://localhost:8080/,你应当能看到:

Welcome to CORS server 😁

如果访问 http://localhost:8080/cors,你会看到类似如下的内容:

Express Server Endpoint /cors.
Express 服务器端点 /cors。

⚛️ 第二步:搭建 React 应用

现在我们的 Express 服务器已经运行起来了,接下来创建一个简单的 React 应用,向该服务器发起 HTTP 请求——并有意触发 CORS 错误,从而学习如何修复它。


📦 创建一个新的 React 项目

在一个与服务器不同的目录中,运行以下命令:

npx create-react-app react-cors-guide

这会在 react-cors-guide 文件夹中构建一个基础的 React 应用骨架。

完成后,进入该项目目录并打开 src/App.js。将其内容替换为以下代码:

import { useEffect } from 'react';
import './App.css';

function App() {
  const makeAPICall = async () => {
    try {
      const response = await fetch('http://localhost:8080/', { mode: 'cors' });
      const data = await response.json();
      console.log({ data });
    } catch (error) {
      console.error('CORS error:', error);
    }
  };

  useEffect(() => {
    makeAPICall();
  }, []);

  return (
    <div className="App">
      <h1>React CORS Guide</h1>
    </div>
  );
}

export default App;


🧠 这里发生了什么?

  • 我们定义了一个 makeAPICall 函数,使用 Fetch APIhttp://localhost:8080/ 发起 GET 请求。

  • { mode: 'cors' } 选项明确告诉浏览器这是一次跨域请求。

  • useEffect 钩子确保在 <App /> 组件挂载后立刻触发该请求。


🔥 预期会出现 CORS 错误

如果你使用如下命令运行 React 应用:

npm start

并查看浏览器的开发者控制台,你很可能会看到 CORS 错误,类似如下:

从源 'http://localhost:3000' 访问 'http://localhost:8080/' 的请求已被 CORS 策略阻止。

这正是浏览器的同源策略在发挥作用:阻止来自不同源的资源访问。

CORS error
CORS 错误

理解 CORS 错误

你在浏览器控制台看到的错误,是一个典型的 CORS 问题。尽管客户端和服务器都运行在 localhost,但它们使用了不同的端口——React 在 localhost:3000,Express 在 localhost:8080

按照同源策略(SOP),这意味着它们被视为不同的源,因此出于安全原因,浏览器会阻止该请求。


⚠️ 典型的 CORS 错误消息

浏览器很可能给出了如下提示:

Access to fetch at 'http://localhost:8080/' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is 
present on the requested resource. If an opaque response serves your needs, 
set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

我们来分解一下:

  • 浏览器阻止了响应,因为它没有在服务器响应中找到 Access-Control-Allow-Origin 头。

  • 提示里甚至给出一个变通方法——将 fetch 的模式设置为 'no-cors'——但那只会返回一个有限的、不透明(opaque)的响应,你无法使用其中的数据。

  • 关键点是:你的客户端并没有做错什么。CORS 不是客户端错误——它是基于服务器响应的、由浏览器强制执行的规则


✅ CORS 应始终在服务器端处理

由于控制浏览器是否允许访问的是服务器的响应,正确的解决方案是配置服务器发送正确的 CORS 头。

在开发阶段,你可以通过代理在客户端侧规避 CORS——但在生产环境中,更干净、也更安全的做法是直接在服务器上启用 CORS。


🔧 在 Express 服务器上启用 CORS

回到 Express 服务器的 app.js,更新 /cors 端点:

app.get('/cors', (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');
  res.send({ msg: 'This has CORS enabled 🎈' });
});

这里发生了什么:

  • Access-Control-Allow-Origin 头设置为 *,意味着任何来源都被允许访问该资源。

  • 这是一个用于演示的快速、简易方式。(在实际生产中,你可能希望只允许特定的来源。)


🔁 更新 React 客户端

现在回到你的 React 应用,将 fetch 的 URL 改为新端点:

const response = await fetch('http://localhost:8080/cors', { mode: 'cors' });

保存更改,必要时重启 React 开发服务器。


🧪 试运行

打开浏览器刷新应用。这一次,浏览器应该会放行该响应,你会在控制台看到如下日志:

{ data: { msg: 'This has CORS enabled 🎈' } }

成功!你已经在正确配置 CORS 的前提下完成了第一次跨域请求。

React CORS
已启用 CORS

确认修复:CORS 生效!

一旦在服务器上正确设置了 CORS 头,错误就会消失,你的 React 应用也能成功接收 JSON 响应。🎉 一切如预期运行!别忘了——你可能需要在更改后重启后端服务器才能使配置生效。


🎯 将 CORS 限制到特定来源

与其使用允许任意来源的通配符(*),你可以将 CORS 限制在某个特定域名上——例如你的 React 开发服务器:

app.get('/cors', (req, res) => {
  res.set('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.send({ msg: 'This has CORS enabled 🎈' });
});

生产环境中推荐这样做,以防止未授权的网站访问你的 API。


⚠️ 当你无法修改服务器时

虽然在服务器端处理是最干净、最稳健的方式,但这并不总是可行。许多开发者在使用第三方 API(如认证、通知、邮件服务等)时会遇到这个问题。在这些情况下,你无法更改服务器的 CORS 策略。

如果发生这种情况,你似乎陷入困境……但真的毫无办法吗?


🧞‍♂️ 变通方案:在 React 中使用代理

这里有一个专门针对 React 开发期的巧妙变通方案:通过开发服务器代理你的 API 请求

可以把代理类比为课堂点名时替同学回答——你的应用让请求看起来来自另一个来源(即服务器的来源),从而绕过浏览器的 SOP 限制。

✏️ 如何设置代理

  1. 在 React 项目根目录下打开 package.json

  2. 新增一个 proxy 字段:

{
  ...
  "proxy": "http://localhost:8080"
}

  1. 重启 React 开发服务器(npm start),现在所有请求都会被静默转发到后端。

例如,当你从 /cors 获取数据时:

const response = await fetch('/cors');

这会在内部被代理到 http://localhost:8080/cors,使该请求对浏览器而言看起来是同源的。

🧪 想要使用第三方服务?

也没问题!你也可以将代理指向它:

{
  ...
  "proxy": "https://randomservice.com"
}

注意事项:

  • 只有非 HTML(通常是 API)请求会被代理。

  • 你的请求的 Accept不应text/html

  • 对于更复杂的场景(例如多个代理),请使用 http-proxy-middleware 来配置自定义代理行为。


🧹 收尾:在 React 中处理 CORS 的最佳实践

关于 CORS,你需要记住以下几点:

  1. 始终在服务器端解决 CORS——这是最可靠、最安全的方案。

  2. 在开发阶段,React 的代理配置可以帮助你在无需修改服务器的情况下避免 CORS 问题。

  3. 如果你无法控制 API 服务器,请联系提供方——或者自建一个代理服务器。

  4. CORS Unblock 这样的 Chrome 扩展或许暂时有效,但绝不应在生产环境使用

  5. 在 fetch 请求中始终显式指定 { mode: 'cors' },以保持行为清晰。

  6. 要理解,大多数基于浏览器的权宜之计在你部署后将不起作用——尽早为生产做规划