NodeJs 第十八章(补充说明请求预检)

118 阅读5分钟

options 请求预检

这里需要补充一个知识点, 前面api接口练习的时候post 请求的时候需要加一个options的判断 请求预检(Preflight Request)是跨域资源共享(CORS,Cross - Origin Resource Sharing)机制中的一个重要环节,主要用于在浏览器发起跨域的非简单请求之前,先向服务器发送一个 OPTIONS 请求,以确认服务器是否允许该跨域请求。以下是关于请求预检的详细解释:

下面将从多个方面对 OPTIONS 请求进行详细解释。

1. 基本概念

OPTIONS 是 HTTP 协议中的一种请求方法,它的主要作用是获取服务器支持的请求方法、请求头信息以及其他相关的通信选项。客户端通过发送 OPTIONS 请求,可以了解服务器针对特定资源所支持的操作和约束条件。

2. 使用场景

2.1 CORS 预检请求

当浏览器发起一个跨域的非简单请求时,会先发送一个 OPTIONS 请求进行预检。简单请求是指满足特定条件的请求,如使用 GETPOSTHEAD 方法,且请求头只包含特定的几个字段(如 AcceptAccept-LanguageContent-Language 等),并且 Content-Typeapplication/x-www-form-urlencodedmultipart/form-datatext/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.简单请求和非简单请求的判断

简单请求

满足以下所有条件的请求被视为简单请求:

  • 请求方法:只使用 GETPOSTHEAD 方法。

  • 请求头:除了由用户代理自动设置的首部字段(如 ConnectionUser - Agent 等)之外,只允许设置以下几个请求头:

    • Accept
    • Accept - Language
    • Content - Language
    • Content - Type,且其值只能是 application/x - www - form - urlencodedmultipart/form - datatext/plain
非简单请求

不满足简单请求条件的请求即为非简单请求,例如:

  • 使用 PUTDELETE 等方法的请求。
  • 设置了自定义请求头(如 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 头信息。如果服务器允许该跨域请求,浏览器将发送真正的请求;如果不允许,浏览器将阻止该请求并在控制台抛出相应的错误信息。