http触发预检请求条件

浏览器会在以下情况下自动发送预检请求(Preflight Request)

简单请求 vs 复杂请求

简单请求(不触发预检)

必须同时满足以下所有条件

1. HTTP 方法限制

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

  • GET
  • HEAD
  • POST
2. 请求头限制

只能包含以下安全头部

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type(但有值的限制)
  • Range(简单范围请求)
3. Content-Type 限制

如果使用 POST 且包含 Content-Type,只能是:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded
4. 其他限制
  • 不能有自定义请求头
  • 不能使用 XMLHttpRequestUpload 对象注册事件监听器
  • 不能使用 ReadableStream 对象

触发预检请求的条件(复杂请求)

满足以下任意一个条件就会触发预检:

1. HTTP 方法

javascript 复制代码
// 这些方法会触发预检
fetch(url, { method: 'PUT' });
fetch(url, { method: 'DELETE' });
fetch(url, { method: 'PATCH' });
fetch(url, { method: 'CONNECT' });

2. 自定义请求头

javascript 复制代码
// 任何自定义头部都会触发预检
fetch(url, {
  headers: {
    'X-Custom-Header': 'value',        // 自定义头部
    'Authorization': 'Bearer token',   // 认证头部
    'X-Requested-With': 'XMLHttpRequest'
  }
});

3. Content-Type 不在简单值范围内

javascript 复制代码
// 这些 Content-Type 会触发预检
fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'    // ❌ 触发预检
  }
});

fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/xml'     // ❌ 触发预检
  }
});

fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'text/html'          // ❌ 触发预检
  }
});

4. 使用凭据

javascript 复制代码
// 设置凭据会触发预检
fetch(url, {
  credentials: 'include'  // 包含 cookies
});

实际示例对比

✅ 简单请求(不触发预检)

javascript 复制代码
// GET 请求
fetch('http://127.0.0.1:3333/list');

// 简单 POST
fetch('http://127.0.0.1:3333/list', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: 'name=john&age=30'
});

// 纯文本 POST
fetch('http://127.0.0.1:3333/list', {
  method: 'POST',
  headers: {
    'Content-Type': 'text/plain'
  },
  body: 'hello world'
});

❌ 复杂请求(触发预检)

javascript 复制代码
// JSON 数据
fetch('http://127.0.0.1:3333/list', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'  // 触发预检
  },
  body: JSON.stringify({name: 'john'})
});

// 自定义头部
fetch('http://127.0.0.1:3333/list', {
  headers: {
    'Authorization': 'Bearer token'     // 触发预检
  }
});

// PUT 方法
fetch('http://127.0.0.1:3333/list', {
  method: 'PUT',                        // 触发预检
  body: 'data'
});

预检请求的内容

当触发预检时,浏览器会发送:

http 复制代码
OPTIONS /list HTTP/1.1
Host: 127.0.0.1:3333
Origin: http://127.0.0.1:5500
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type

服务器需要响应:

http 复制代码
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://127.0.0.1:5500
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

避免预检的技巧

如果想避免预检请求:

  1. 使用 GET/HEAD/POST 方法
  2. 避免自定义头部
  3. POST 时使用 application/x-www-form-urlencodedtext/plain
  4. 不使用认证相关头部

但在现代 Web 开发中,JSON API 很常见,所以预检请求是不可避免的,正确配置 CORS 才是解决方案。

相关推荐
Jony_2 天前
高可用移动网络连接
网络协议
chilix3 天前
Linux 跨网段路由转发配置
网络协议
DianSan_ERP4 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
呉師傅4 天前
火狐浏览器报错配置文件缺失如何解决#操作技巧#
运维·网络·windows·电脑
gihigo19984 天前
基于TCP协议实现视频采集与通信
网络协议·tcp/ip·音视频
2501_946205524 天前
晶圆机器人双臂怎么选型?适配2-12寸晶圆的末端效应器有哪些?
服务器·网络·机器人
linux kernel4 天前
第七部分:高级IO
服务器·网络
数字护盾(和中)4 天前
BAS+ATT&CK:企业主动防御的黄金组合
服务器·网络·数据库
~远在太平洋~4 天前
Debian系统如何删除多余的kernel
linux·网络·debian
unfeeling_4 天前
Keepalived实验
linux·服务器·网络