减少 CORS 预请求次数
通过简单请求和缓存策略减少 CORS 预检请求
问题
跨域请求时,浏览器会发送 OPTIONS 预检请求,增加了请求延迟。如何减少这些预请求的次数?
解答
1. 理解预检请求的触发条件
只有”非简单请求”才会触发预检。简单请求需满足:
- 方法为
GET、HEAD、POST之一 - 仅使用安全请求头:
Accept、Accept-Language、Content-Language、Content-Type Content-Type仅限:application/x-www-form-urlencoded、multipart/form-data、text/plain
2. 方法一:使用简单请求
// ❌ 会触发预检:使用了自定义请求头
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // 非简单请求头
'X-Custom-Header': 'value' // 自定义请求头
},
body: JSON.stringify({ name: 'test' })
});
// ✅ 不触发预检:符合简单请求条件
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'name=test&age=18'
});
3. 方法二:设置预检缓存
服务端设置 Access-Control-Max-Age,让浏览器缓存预检结果:
// Node.js Express 示例
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://example.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 缓存预检结果 86400 秒(24小时)
// 在此期间,相同请求不再发送 OPTIONS
res.header('Access-Control-Max-Age', '86400');
if (req.method === 'OPTIONS') {
return res.sendStatus(204);
}
next();
});
4. 方法三:合并请求
// ❌ 多次请求,多次预检
await fetch('/api/user');
await fetch('/api/orders');
await fetch('/api/products');
// ✅ 合并为一次请求
await fetch('/api/batch', {
method: 'POST',
body: JSON.stringify({
requests: ['/user', '/orders', '/products']
})
});
5. 方法四:同源代理
通过同源服务器代理请求,完全避免跨域:
// 前端请求同源接口
fetch('/api/proxy/external-data');
// 后端代理转发
app.get('/api/proxy/external-data', async (req, res) => {
const data = await fetch('https://external-api.com/data');
res.json(await data.json());
});
关键点
- 简单请求不触发预检:GET/HEAD/POST + 安全请求头 + 限定 Content-Type
Access-Control-Max-Age可缓存预检结果,单位为秒- 避免自定义请求头,尽量用标准头
- 合并多个 API 请求减少总请求数
- 同源代理可完全规避 CORS 问题
目录