CORS简单请求的条件

判断 CORS 请求是否为简单请求的条件

问题

CORS 中哪些请求属于简单请求?简单请求和预检请求有什么区别?

解答

简单请求必须同时满足以下所有条件:

1. 请求方法限制

只能是以下三种方法之一:

  • GET
  • HEAD
  • POST

2. 请求头限制

只能包含以下头字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type(有额外限制)

3. Content-Type 限制

如果有 Content-Type,只能是以下三种:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

4. 其他限制

  • 请求中没有使用 ReadableStream 对象
  • XMLHttpRequest.upload 没有注册事件监听器

示例对比

// ✅ 简单请求
fetch('https://api.example.com/data', {
  method: 'GET'
});

// ✅ 简单请求
fetch('https://api.example.com/submit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: 'name=test&value=123'
});

// ❌ 非简单请求 - Content-Type 不符合
fetch('https://api.example.com/api', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'  // 触发预检
  },
  body: JSON.stringify({ name: 'test' })
});

// ❌ 非简单请求 - 自定义头
fetch('https://api.example.com/api', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer token',  // 触发预检
    'X-Custom-Header': 'value'        // 触发预检
  }
});

// ❌ 非简单请求 - PUT 方法
fetch('https://api.example.com/resource', {
  method: 'PUT',  // 触发预检
  body: 'data'
});

简单请求 vs 预检请求

简单请求流程:
浏览器 -------- GET /data --------> 服务器
浏览器 <------- 响应 + CORS头 ----- 服务器

预检请求流程:
浏览器 -------- OPTIONS /api -----> 服务器  (预检)
浏览器 <------- 204 + CORS头 ------ 服务器
浏览器 -------- POST /api --------> 服务器  (实际请求)
浏览器 <------- 响应 -------------- 服务器

关键点

  • 简单请求直接发送,非简单请求先发 OPTIONS 预检
  • application/json 不是简单请求,会触发预检
  • 自定义请求头(如 Authorization)会触发预检
  • PUTDELETEPATCH 方法都会触发预检
  • 预检请求的结果可以被缓存,通过 Access-Control-Max-Age 控制