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 才是解决方案。

相关推荐
洋葱圈儿66643 分钟前
nat静态地址转化
网络·智能路由器
OPTree4121 小时前
H3C网络设备 实验三: 搭建两个局域网,使两个局域网相互通信(路由器,自动分配ip,DHCP协议)
网络·tcp/ip·智能路由器
WTCLLB1 小时前
netgear r6220 路由器,刷openwrt后,系统备份还原
linux·网络·智能路由器·openwrt
做运维的阿瑞2 小时前
Linux系统性能监控与故障定位实战:CPU/内存/I/O/网络
linux·运维·网络
CiLerLinux3 小时前
第五十二章 ESP32S3 UDP 实验
网络·单片机·嵌入式硬件·网络协议·udp
切糕师学AI3 小时前
P2P技术
网络·网络协议·p2p
尤利乌斯.X4 小时前
复杂网络仿真从入门到精通:0 学习路线
网络·学习·matlab·仿真·复杂网络
Chandler245 小时前
一图掌握 网络协议 核心要点
网络协议·tcp/ip·计算机网络·http
JJJJ_iii6 小时前
【深度学习03】神经网络基本骨架、卷积、池化、非线性激活、线性层、搭建网络
网络·人工智能·pytorch·笔记·python·深度学习·神经网络
海阳宜家电脑6 小时前
SQL Server连接字符串
服务器·网络