大多数初级前端程序员,在通过浏览器F12的调试工具调试网络请求时,可能都会有一个发现,在进行POST请求时,明明代码里只请求了一次,为什么network里发送了两次呢,难道我代码出bug了?带着疑问点开第一个请求才发现,原来第一个是OPTIONS类型的请求,第二个才是我代码里写的POST类型的请求。那为什么,POST请求之前默认伴随着一个OPTIONS请求呢?
我本人也是在第一份实际工作中,才发现了这个事情,带着疑问查询了一些资料,才知晓了其中缘由。在这个过程中也了解到了一些不常用的HTTP
协议请求的方法以及它们的作用,比如OPTIONS
。
公众号:Code程序人生,个人网站:https://creatorblog.cn
可能大多数程序员,职业生涯里,90%遇到和创造的接口都是GET
和POST
,秉持着"不用就不学"的原则,越来越多的HTTP
协议的请求方法淡化在了大家视野里,自然在遇到的时候就不知道它是干啥的了。
背景
在Web
开发中,我们经常会遇到跨域请求的问题。当前端应用试图从一个源(origin)
上的Web
页面访问另一个源上的资源时,浏览器会执行跨域请求,其中POST
请求常常会伴随着两次发送:一次OPTIONS
请求(CORS
预检)和一次实际的POST
请求。
为什么会有这两次请求?下文我们继续深入解释这个问题,逐步探究CORS
预检的原因和机制。
什么是CORS(跨源资源共享)
CORS
是一种浏览器的安全策略,用于控制一个源(domain、protocol、port
的组合)的Web
页面是否可以请求另一个源的资源。CORS
通过在服务器响应头中添加特定的字段,告诉浏览器是否允许来自其他源的请求。
为什么POST请求需要CORS预检
POST
请求通常用于向服务器提交数据,但由于安全性考虑,浏览器会限制跨域POST
请求。在实际发送POST
请求之前,浏览器会发送一个OPTIONS
请求,以便确认目标服务器是否允许实际的POST
请求。
GET请求一定不需要CORS预检吗
CORS
预检是一种安全机制,用于控制跨域请求的访问权限。对于简单请求(Simple Requests)
,包括使用GET
、HEAD
、POST
其中一种方法,且只使用了以下几种简单请求头(Simple Request Headers
)的请求,浏览器会自动处理CORS
,无需进行预检:
- Accept
- Accept-Language
- Content-Language
- Content-Type(仅限于 application/x-www-form-urlencoded、multipart/form-data、text/plain)
因此,GET
请求通常不会触发CORS
预检。只有当你的请求是跨域的、使用了非简单请求头、或者使用了不支持的HTTP
方法时,才会触发CORS
预检。对于非简单请求,浏览器会在实际请求之前发送一个OPTIONS
请求,用来确认服务器是否支持跨域请求。而对于简单请求,浏览器会直接发送实际的GET
请求,不需要进行预检。
CORS预检的过程
- 浏览器发送OPTIONS请求:
当浏览器发现一个跨域的POST
请求时,它首先发送一个OPTIONS
请求到目标服务器,这是CORS
预检的开始。
- 服务器响应CORS头信息:
服务器接收到OPTIONS
请求后,检查请求中的信息,并返回响应。响应中包含了CORS
头信息,其中包括允许的HTTP
方法、允许的请求头等。如果服务器返回的CORS
头信息允许实际的POST
请求,浏览器才会继续发送实际的POST
请求。
服务端示例代码
在服务器端,你需要配置CORS
,以允许来自特定源的POST
请求。以下是Nodejs
Express
框架的示例:
const express = require('express');
const app = express();
// 配置CORS,允许所有源的POST请求
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*'); // 允许所有源
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); // 允许的HTTP方法
res.header('Access-Control-Allow-Headers', 'Content-Type'); // 允许的请求头
next();
});
// 实际的POST请求处理
app.post('/api/data', (req, res) => {
// 处理POST请求的逻辑
res.send('POST请求成功!');
});
app.listen(3000, () => {
console.log('服务器启动在端口 3000');
});
在上述代码中,通过配置Access-Control-Allow-Origin
、Access-Control-Allow-Methods
和Access-Control-Allow-Headers
等响应头信息,服务器明确指定了允许的源、HTTP
方法和请求头。
总结
POST
请求发送两次的现象是因为浏览器在执行跨域的POST
请求时,为了确保安全性,会发送一个OPTIONS
请求进行CORS
预检。服务器的CORS
配置决定了是否允许实际的POST
请求。理解CORS
预检的过程,能够帮助我们更好地处理跨域请求问题,确保Web
应用的安全性和稳定性。