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

相关推荐
斯~内克19 分钟前
深入解析域名并发请求限制与HTTP/2多路复用技术
网络·网络协议·http
weixin_4569042725 分钟前
基于UDP的SNMP协议
网络·网络协议·udp
机器视觉知识推荐、就业指导1 小时前
手动开发一个TCP客户端调试工具(一):了解Qt中TCP通信原理与核心类
网络·qt·tcp/ip
穗 禾1 小时前
github与git新手教程(快速访问github)
网络·git·github
都给我1 小时前
零信任网络概念及在网络安全中的应用
网络·安全·web安全
卓豪终端管理2 小时前
电脑远程关机的重要性
运维·网络·devops
van叶~3 小时前
Linux网络-------3.应⽤层协议HTTP
linux·网络·http
Wmenghu3 小时前
java获取电脑公网IP和内网IP
服务器·网络·tcp/ip
小猪咪piggy4 小时前
【JavaEE】(7) 网络原理 TCP/IP 协议
运维·服务器·网络
是瑶瑶子啦5 小时前
【AlphaFold3】网络架构篇(5)|Template embedding & Pairformer stack
网络·embedding