正在加载,请稍候…

如何修复 CORS 错误:开发者分步指南

理解 CORS 错误发生的原因并正确修复——涵盖预检请求、服务端头部、凭据以及 Express、Nginx 和云 API 中的常见错误。

如何修复 CORS 错误:开发者分步指南

如何修复 CORS 错误

CORS 是一种浏览器安全特性,而非服务器限制。你的服务器正常接收请求——但浏览器阻止响应到达你的 JavaScript。CORS 错误永远不会出现在 curl、Postman 或服务器到服务器的调用中。

同源策略(Same-Origin Policy)阻止 https://app.example.com 上的 JavaScript 读取来自 https://api.other.com 的响应,除非 API 通过 CORS 头部明确允许。

如何修复 CORS 错误:开发者分步指南插图

阅读错误信息

Chrome:Access to fetch at 'https://api.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.

常见变体:

  • "No Access-Control-Allow-Origin header" → 服务器未发送 CORS 头部
  • "Value not equal to supplied origin" → 配置的源不正确
  • "Response to preflight doesn't pass access control check" → OPTIONS 请求失败
  • "Allow-Credentials must be true" → 未启用凭据

修复 1:在服务器上添加 CORS 头部

Express / Node.js

const cors = require('cors');

// 允许特定源(生产环境)
app.use(cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400,
}));

// 多个允许的源
const allowedOrigins = ['https://app.example.com', 'http://localhost:3000'];
app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) callback(null, true);
    else callback(new Error('Not allowed by CORS'));
  },
  credentials: true,
}));

如何修复 CORS 错误:开发者分步指南插图

Django

# pip install django-cors-headers
INSTALLED_APPS = [..., 'corsheaders']
MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware', ...]
CORS_ALLOWED_ORIGINS = ['https://app.example.com']
CORS_ALLOW_CREDENTIALS = True

FastAPI

from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(CORSMiddleware,
  allow_origins=['https://app.example.com'],
  allow_credentials=True,
  allow_methods=['*'],
  allow_headers=['*'],
)

Nginx

location /api/ {
  if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' 'https://app.example.com';
    add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'Content-Type,Authorization';
    return 204;
  }
  add_header 'Access-Control-Allow-Origin' 'https://app.example.com' always;
  add_header 'Access-Control-Allow-Credentials' 'true' always;
}

如何修复 CORS 错误:开发者分步指南插图

修复 2:预检请求失败

复杂请求(DELETE、PUT、自定义头部如 Authorization)会触发 OPTIONS 预检。如果 OPTIONS 返回 404 或缺少头部,实际请求永远不会发生。

// Express:在认证中间件之前处理 OPTIONS
app.options('*', cors());
app.use(cors({ ... }));
app.use(authMiddleware);  // 认证在 CORS 之后

// 跳过 OPTIONS 预检的认证
function authMiddleware(req, res, next) {
  if (req.method === 'OPTIONS') return next();
  // 验证 token...
}

修复 3:凭据 + Cookie

fetch(url, { credentials: 'include' });       // fetch
axios.get(url, { withCredentials: true });    // axios

服务器必须使用特定源,不能使用通配符:

# 错误:Access-Control-Allow-Origin: *  +  Access-Control-Allow-Credentials: true
# 正确:Access-Control-Allow-Origin: https://app.example.com
#        Access-Control-Allow-Credentials: true

修复 4:你无法控制的 API

通过你自己的后端代理:

app.get('/api/proxy', async (req, res) => {
  const data = await fetch('https://third-party-api.com/data');
  res.json(await data.json());
});

常见错误

  1. 重复的 CORS 头部 — Nginx 和 Express 都添加头部;浏览器拒绝重复
  2. 错误响应缺少 CORS — 401/500 错误可能缺少头部,使用 always 标志
  3. 尾部斜杠不匹配https://app.comhttps://app.com/ 是不同的源
  4. 未重启服务器 — 浏览器可能缓存预检结果,持续 Access-Control-Max-Age

→ 查看 HTTP 状态码:HTTP Status Codes