常识来了
白蓝主题五 · 清爽阅读
首页  > 软件进阶

HTTP请求预检请求是什么

HTTP请求预检请求是什么

你在写前端代码时,可能遇到过这样的情况:明明只发了一次请求,但在浏览器的开发者工具里却看到发了两次。第一次是 OPTIONS,第二次才是你真正想发的 POSTPUT。这个多出来的 OPTIONS 请求,就是“预检请求”(Preflight Request)。

什么时候会触发预检

预检不是每次请求都来,它只在跨域(CORS)且满足“非简单请求”条件时才会出现。简单说,如果你的请求带了自定义头、用了除 GETPOSTHEAD 以外的方法,或者 Content-Typeapplication/json 之外的类型(比如 text/plain),浏览器就会先发个 OPTIONS 探探路。

比如你用 fetch 发个带 token 的请求:

fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer xyz'
},
body: JSON.stringify({ name: 'test' })
});

虽然看着就一次,但因为加了 Authorization 头,浏览器觉得这事儿得先问问服务器同不同意,于是先发个 OPTIONS 请求。

预检请求长什么样

那个 OPTIONS 请求里会带上几个关键头信息:

  • Access-Control-Request-Method:告诉你接下来要用什么方法,比如 POST
  • Access-Control-Request-Headers:列出所有自定义头,比如 Authorization, Content-Type

服务器收到后,得判断这些方法和头是不是允许的。如果允许,就返回 200 并带上 Access-Control-Allow-MethodsAccess-Control-Allow-Headers。浏览器一看,哦,能干,才继续发真正的请求。

怎么避免频繁预检

预检虽然安全,但多一次网络往返,总归有开销。如果你控制得了后端,可以加个响应头让浏览器缓存预检结果:

Access-Control-Max-Age: 86400

这表示这次预检结果可以缓存一天,期间同样的请求就不用再预检了。注意,不同浏览器对最大缓存时间有限制,Chrome 是 24 小时,别设太离谱。

还有一点,尽量用简单请求能绕开预检。比如把 Content-Type 改成 application/x-www-form-urlencoded,或者避免加自定义头,就能少一次请求。

预检请求就像进小区前保安先打电话确认业主是否在家。虽然烦了点,但为了安全,也挺必要。