服务端配置 CORS(跨域资源共享)的原理本质是 浏览器与服务器之间的安全协商机制。其核心在于服务器通过特定的 HTTP 响应头声明允许哪些外部源(Origin)访问资源,浏览器根据这些响应头决定是否放行跨域请求。以下是详细原理分解:
一、核心流程:浏览器与服务端的协作机制
场景:网页 https://web.com
请求 https://api.com/data
-
浏览器发起跨域请求
- 自动在请求头中添加
Origin: https://web.com
(表明请求来源)。
- 自动在请求头中添加
-
服务端响应
- 检查
Origin
值是否在允许列表中。 - 若允许,则在响应头中添加 CORS 相关字段(如
Access-Control-Allow-Origin: https://web.com
)。 - 若拒绝,不添加 CORS 头或返回错误(浏览器会拦截响应)。
- 检查
-
浏览器验证响应头
- 检查响应头是否包含
Access-Control-Allow-Origin
且值与当前Origin
匹配(或为*
)。 - 验证通过 → 解除拦截,网页可读取响应数据。
- 验证失败 → 抛出 CORS 错误(如
No 'Access-Control-Allow-Origin' header
)。
- 检查响应头是否包含
二、关键 HTTP 响应头字段解析
服务器通过以下头字段声明跨域规则:
响应头字段 | 作用 | 示例 |
---|---|---|
Access-Control-Allow-Origin | 必选,声明允许访问的源(域名) | https://web.com 或 * |
Access-Control-Allow-Methods | 声明允许的 HTTP 方法(如 GET、POST) | GET, POST, PUT |
Access-Control-Allow-Headers | 声明允许客户端携带的请求头(如 Content-Type ) | Content-Type, Authorization |
Access-Control-Allow-Credentials | 是否允许发送 Cookie 等凭证(需客户端设置 withCredentials: true ) | true |
Access-Control-Max-Age | 预检请求(OPTIONS)的缓存时间(秒),减少重复预检 | 86400 (24小时) |
⚠️ 注意:若请求需携带 Cookie(凭证),则:
- 服务端必须设置
Access-Control-Allow-Credentials: true
- 服务端的
Access-Control-Allow-Origin
不能为*
,必须明确指定域名(如https://web.com
)- 客户端需设置
withCredentials: true
(如 Fetch API 或 Axios)。
三、预检请求(Preflight Request):复杂请求的二次确认
当请求满足以下任一条件时,浏览器会先发送 OPTIONS 预检请求(非简单请求):
- 使用了
PUT
、DELETE
等非简单方法(简单方法仅限GET
、POST
、HEAD
)。 - 携带了自定义请求头(如
Authorization
)。 Content-Type
为application/json
等非简单类型(简单类型仅限application/x-www-form-urlencoded
、multipart/form-data
、text/plain
)。
预检请求工作流程:
四、CORS 的安全本质:服务端控制权限
-
主动权在服务端
- 浏览器只是执行者,实际放行权由服务端通过响应头控制。
- 若服务器未返回正确的 CORS 头,即使接口本身能正常响应(如用 Postman 测试成功),浏览器仍会拦截。
-
防御恶意网站
- 假设用户访问了恶意网站
evil.com
,该网站尝试请求bank.com
的 API:bank.com
的服务器检测到Origin: evil.com
不在白名单中 → 不返回 CORS 头。- 浏览器拦截响应 →
evil.com
无法读取bank.com
的数据。
- 假设用户访问了恶意网站
五、配置示例:Node.js 中的 CORS 中间件
const express = require('express');
const cors = require('cors');const app = express();// 基础配置:允许所有源访问(慎用!)
app.use(cors());// 精细化配置(推荐)
app.use(cors({origin: 'https://web.com', // 仅允许指定源methods: ['GET', 'POST'], // 允许的方法allowedHeaders: ['Content-Type'], // 允许的请求头credentials: true, // 允许携带凭证maxAge: 86400 // 预检缓存时间
}));app.get('/data', (req, res) => {res.json({ data: "跨域数据返回成功!" });
});
六、常见误区澄清
误区 | 真相 |
---|---|
“CORS 是服务端的安全漏洞” | CORS 是安全机制,没有它浏览器会默认禁止跨域 |
“JSONP 能替代 CORS” | JSONP 仅支持 GET,且存在安全风险(如 XSS) |
“前端代码可绕过 CORS 限制” | 浏览器会强制检查响应头,前端无法绕过 |
“服务端不配置 CORS = 接口无法访问” | 接口仍可被 curl、Postman 等工具调用,但浏览器会拦截 |
总结:CORS 的核心原理
通过这一机制,CORS 在不牺牲安全性的前提下实现了可控的跨域资源共享,成为现代 Web 开发的基石技术。