复杂请求预检检查内容

CORS 预检请求检查的内容及服务器响应方式

问题

跨域复杂请求会触发预检请求(Preflight Request),预检请求具体检查什么内容?

解答

什么是复杂请求

满足以下任一条件的请求为复杂请求:

  • 使用 PUTDELETEPATCH 等方法
  • 包含自定义请求头(如 X-Token
  • Content-Type 不是 application/x-www-form-urlencodedmultipart/form-datatext/plain

预检请求检查内容

浏览器发送 OPTIONS 请求,携带以下头部询问服务器:

请求头作用
Origin请求来源
Access-Control-Request-Method实际请求将使用的方法
Access-Control-Request-Headers实际请求将携带的自定义头

服务器响应

服务器需返回对应的允许头:

响应头作用
Access-Control-Allow-Origin允许的来源
Access-Control-Allow-Methods允许的方法
Access-Control-Allow-Headers允许的请求头
Access-Control-Max-Age预检结果缓存时间(秒)

示例

// 前端发起复杂请求
fetch('https://api.example.com/data', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'X-Token': 'abc123'  // 自定义头,触发预检
  },
  body: JSON.stringify({ name: 'test' })
});
# 浏览器自动发送的预检请求
OPTIONS /data HTTP/1.1
Host: api.example.com
Origin: https://mysite.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, X-Token
# 服务器响应
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://mysite.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, X-Token
Access-Control-Max-Age: 86400
// Node.js 服务端处理示例
app.options('/data', (req, res) => {
  res.set({
    'Access-Control-Allow-Origin': req.headers.origin,
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
    'Access-Control-Allow-Headers': 'Content-Type, X-Token',
    'Access-Control-Max-Age': '86400'
  });
  res.status(204).end();
});

关键点

  • 预检请求使用 OPTIONS 方法,由浏览器自动发起
  • 检查三项:来源(Origin)、请求方法、自定义请求头
  • 服务器必须返回对应的 Access-Control-Allow-*
  • Access-Control-Max-Age 可缓存预检结果,避免重复请求
  • 预检通过后,浏览器才会发送实际请求