服务端配置 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 预检请求(非简单请求):
预检请求工作流程:
#mermaid-svg-eoXfYt6ZK3wHQ67B {font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-eoXfYt6ZK3wHQ67B .error-icon{fill:#552222;}#mermaid-svg-eoXfYt6ZK3wHQ67B .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eoXfYt6ZK3wHQ67B .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-eoXfYt6ZK3wHQ67B .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eoXfYt6ZK3wHQ67B .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eoXfYt6ZK3wHQ67B .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eoXfYt6ZK3wHQ67B .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eoXfYt6ZK3wHQ67B .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eoXfYt6ZK3wHQ67B .marker.cross{stroke:#333333;}#mermaid-svg-eoXfYt6ZK3wHQ67B svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eoXfYt6ZK3wHQ67B .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-eoXfYt6ZK3wHQ67B text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-eoXfYt6ZK3wHQ67B .actor-line{stroke:grey;}#mermaid-svg-eoXfYt6ZK3wHQ67B .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-eoXfYt6ZK3wHQ67B .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-eoXfYt6ZK3wHQ67B #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-eoXfYt6ZK3wHQ67B .sequenceNumber{fill:white;}#mermaid-svg-eoXfYt6ZK3wHQ67B #sequencenumber{fill:#333;}#mermaid-svg-eoXfYt6ZK3wHQ67B #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-eoXfYt6ZK3wHQ67B .messageText{fill:#333;stroke:#333;}#mermaid-svg-eoXfYt6ZK3wHQ67B .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-eoXfYt6ZK3wHQ67B .labelText,#mermaid-svg-eoXfYt6ZK3wHQ67B .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-eoXfYt6ZK3wHQ67B .loopText,#mermaid-svg-eoXfYt6ZK3wHQ67B .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-eoXfYt6ZK3wHQ67B .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-eoXfYt6ZK3wHQ67B .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-eoXfYt6ZK3wHQ67B .noteText,#mermaid-svg-eoXfYt6ZK3wHQ67B .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-eoXfYt6ZK3wHQ67B .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-eoXfYt6ZK3wHQ67B .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-eoXfYt6ZK3wHQ67B .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-eoXfYt6ZK3wHQ67B .actorPopupMenu{position:absolute;}#mermaid-svg-eoXfYt6ZK3wHQ67B .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-eoXfYt6ZK3wHQ67B .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-eoXfYt6ZK3wHQ67B .actor-man circle,#mermaid-svg-eoXfYt6ZK3wHQ67B line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-eoXfYt6ZK3wHQ67B :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}BrowserServerOPTIONS 预检请求携带:Origin: https://web.comAccess-Control-Request-Method: PUTAccess-Control-Request-Headers: Content-Type响应预检结果返回:Access-Control-Allow-Origin: https://web.comAccess-Control-Allow-Methods: PUTAccess-Control-Allow-Headers: Content-Type发送真实请求(PUT)返回真实数据BrowserServer
四、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 的核心原理
#mermaid-svg-sl4ODSvoOnTmtYQW {font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-sl4ODSvoOnTmtYQW .error-icon{fill:#552222;}#mermaid-svg-sl4ODSvoOnTmtYQW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sl4ODSvoOnTmtYQW .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-sl4ODSvoOnTmtYQW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sl4ODSvoOnTmtYQW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sl4ODSvoOnTmtYQW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sl4ODSvoOnTmtYQW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sl4ODSvoOnTmtYQW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sl4ODSvoOnTmtYQW .marker.cross{stroke:#333333;}#mermaid-svg-sl4ODSvoOnTmtYQW svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sl4ODSvoOnTmtYQW .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-sl4ODSvoOnTmtYQW .cluster-label text{fill:#333;}#mermaid-svg-sl4ODSvoOnTmtYQW .cluster-label span{color:#333;}#mermaid-svg-sl4ODSvoOnTmtYQW .label text,#mermaid-svg-sl4ODSvoOnTmtYQW span{fill:#333;color:#333;}#mermaid-svg-sl4ODSvoOnTmtYQW .node rect,#mermaid-svg-sl4ODSvoOnTmtYQW .node circle,#mermaid-svg-sl4ODSvoOnTmtYQW .node ellipse,#mermaid-svg-sl4ODSvoOnTmtYQW .node polygon,#mermaid-svg-sl4ODSvoOnTmtYQW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sl4ODSvoOnTmtYQW .node .label{text-align:center;}#mermaid-svg-sl4ODSvoOnTmtYQW .node.clickable{cursor:pointer;}#mermaid-svg-sl4ODSvoOnTmtYQW .arrowheadPath{fill:#333333;}#mermaid-svg-sl4ODSvoOnTmtYQW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sl4ODSvoOnTmtYQW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sl4ODSvoOnTmtYQW .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-sl4ODSvoOnTmtYQW .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-sl4ODSvoOnTmtYQW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sl4ODSvoOnTmtYQW .cluster text{fill:#333;}#mermaid-svg-sl4ODSvoOnTmtYQW .cluster span{color:#333;}#mermaid-svg-sl4ODSvoOnTmtYQW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sl4ODSvoOnTmtYQW :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}携带 Origin 头合法非法浏览器请求服务端检查 Origin 合法性添加 CORS 响应头不添加 CORS 头浏览器放行请求浏览器拦截请求
通过这一机制,CORS 在不牺牲安全性的前提下实现了可控的跨域资源共享,成为现代 Web 开发的基石技术。
评论前必须登录!
注册