options 请求预检
这里需要补充一个知识点, 前面api接口练习的时候post 请求的时候需要加一个options的判断
请求预检(Preflight Request)是跨域资源共享(CORS,Cross - Origin Resource Sharing)机制中的一个重要环节,主要用于在浏览器发起跨域的非简单请求之前,先向服务器发送一个 OPTIONS
请求,以确认服务器是否允许该跨域请求。以下是关于请求预检的详细解释:
下面将从多个方面对 OPTIONS
请求进行详细解释。
1. 基本概念
OPTIONS
是 HTTP 协议中的一种请求方法,它的主要作用是获取服务器支持的请求方法、请求头信息以及其他相关的通信选项。客户端通过发送 OPTIONS
请求,可以了解服务器针对特定资源所支持的操作和约束条件。
2. 使用场景
2.1 CORS 预检请求
当浏览器发起一个跨域的非简单请求时,会先发送一个 OPTIONS
请求进行预检。简单请求是指满足特定条件的请求,如使用 GET
、POST
或 HEAD
方法,且请求头只包含特定的几个字段(如 Accept
、Accept-Language
、Content-Language
等),并且 Content-Type
为 application/x-www-form-urlencoded
、multipart/form-data
或 text/plain
。非简单请求则需要进行预检,以确保服务器允许该请求。
2.2 发现服务器能力
客户端可以通过发送 OPTIONS
请求来了解服务器支持的 HTTP 方法和请求头,从而在后续的请求中使用合适的方法和头信息。
3. 请求和响应示例
3.1 请求示例
以下是一个使用 curl
工具发送 OPTIONS
请求的示例:
curl -X OPTIONS https://example.com/api/resource
在浏览器环境中,当进行跨域的非简单请求时,浏览器会自动发送 OPTIONS
请求。例如,使用 fetch
API 发送一个带有自定义请求头的跨域 POST
请求:
fetch('https://example.com/api/resource', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
},
body: JSON.stringify({ data: 'example' })
})
3.2 响应示例
服务器对 OPTIONS
请求的响应通常包含以下重要的响应头:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://client.example
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
HTTP/1.1 204 No Content
:状态码 204 表示请求已成功处理,但响应中没有实体内容。Access-Control-Allow-Origin
:指定允许访问该资源的外域 URI。可以使用*
表示允许所有来源,但在生产环境中建议指定具体的域名。Access-Control-Allow-Methods
:指定允许的 HTTP 请求方法。Access-Control-Allow-Headers
:指定允许的请求头。Access-Control-Max-Age
:指定预检请求结果的缓存时间(秒),避免频繁发送预检请求。
4. 服务器端处理
4.1 原生 Node.js
const http = require('http');
const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Max-Age', '86400');
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
} else {
// 处理其他请求
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, World!');
}
});
const port = 3000;
server.listen(port, () => {
console.log(`Server running on port ${port}`);
});
5.为什么需要请求预检
浏览器出于安全考虑,实施了同源策略(Same - Origin Policy)。同源策略规定,浏览器只允许访问同源(协议、域名和端口都相同)的资源。当需要访问跨域资源时,就需要通过 CORS 机制来突破这个限制。
对于简单请求,浏览器会直接发送请求并在响应中检查 CORS 相关的响应头来决定是否允许访问。但对于非简单请求,由于这些请求可能对服务器资源有较大影响,浏览器会先发送一个预检请求,在得到服务器的明确许可后,才会发送真正的请求。
6.简单请求和非简单请求的判断
简单请求
满足以下所有条件的请求被视为简单请求:
-
请求方法:只使用
GET
、POST
或HEAD
方法。 -
请求头:除了由用户代理自动设置的首部字段(如
Connection
、User - Agent
等)之外,只允许设置以下几个请求头:Accept
Accept - Language
Content - Language
Content - Type
,且其值只能是application/x - www - form - urlencoded
、multipart/form - data
或text/plain
非简单请求
不满足简单请求条件的请求即为非简单请求,例如:
- 使用
PUT
、DELETE
等方法的请求。 - 设置了自定义请求头(如
Authorization
)的请求。 Content - Type
的值为application/json
等非简单请求允许的值的请求。
7.请求预检的工作流程
步骤 1:发送 OPTIONS
预检请求
当浏览器检测到一个跨域的非简单请求时,会自动先发送一个 OPTIONS
请求到目标服务器。这个 OPTIONS
请求包含以下重要信息:
-
请求方法:
OPTIONS
-
请求头:
Origin
:表示发起请求的源(协议、域名和端口)。Access - Control - Request - Method
:指示后续真正请求将使用的 HTTP 方法。Access - Control - Request - Headers
:指示后续真正请求将携带的额外请求头。
以下是一个 OPTIONS
预检请求的示例:
OPTIONS /api/resource HTTP/1.1
Host: example.com
Origin: https://client.example
Access - Control - Request - Method: PUT
Access - Control - Request - Headers: Content - Type, Authorization
步骤 2:服务器响应预检请求
服务器接收到 OPTIONS
请求后,需要检查请求中的信息,并在响应中返回相应的 CORS 头信息。常见的响应头包括:
Access - Control - Allow - Origin
:指定允许访问该资源的外域 URI。可以使用*
表示允许所有来源,但在生产环境中建议指定具体的域名。Access - Control - Allow - Methods
:指定允许的 HTTP 请求方法。Access - Control - Allow - Headers
:指定允许的请求头。Access - Control - Max - Age
:指定预检请求结果的缓存时间(秒),避免频繁发送预检请求。
以下是一个服务器对 OPTIONS
请求的响应示例:
HTTP/1.1 204 No Content
Access - Control - Allow - Origin: https://client.example
Access - Control - Allow - Methods: GET, POST, PUT, DELETE
Access - Control - Allow - Headers: Content - Type, Authorization
Access - Control - Max - Age: 86400
步骤 3:浏览器根据响应决定是否发送真正的请求
浏览器接收到服务器对 OPTIONS
请求的响应后,会检查响应中的 CORS 头信息。如果服务器允许该跨域请求,浏览器将发送真正的请求;如果不允许,浏览器将阻止该请求并在控制台抛出相应的错误信息。