跨域资源共享(CORS)的原理与实现
字数 1899 2025-11-18 04:16:25

跨域资源共享(CORS)的原理与实现

1. 问题描述

跨域资源共享(CORS)是一种机制,允许网页从不同域(协议、域名、端口任一不同)的服务器访问资源。浏览器的同源策略(Same-Origin Policy)默认禁止跨域请求,但实际业务中(如前后端分离架构)常需跨域访问资源,CORS 通过特定 HTTP 头实现安全的跨域通信。


2. CORS 的基本原理

CORS 的核心是浏览器与服务器通过 HTTP 头协商跨域权限。整个过程分为两类请求:

  • 简单请求:直接发送跨域请求,服务器返回 Access-Control-Allow-Origin 头授权。
  • 预检请求:非简单请求需先发送 OPTIONS 请求,验证通过后再发送实际请求。

2.1 简单请求的条件

满足以下所有条件时,浏览器会将其视为简单请求:

  1. 请求方法为 GETPOSTHEAD
  2. 请求头仅包含以下字段:
    • AcceptAccept-LanguageContent-LanguageContent-Type(仅限 application/x-www-form-urlencodedmultipart/form-datatext/plain)。
  3. 未使用自定义头(如 Authorization)或特殊头(如 Range)。

2.2 简单请求的流程

  1. 浏览器直接发送跨域请求,并在请求头中自动添加 Origin(例如 Origin: https://frontend.com)。
  2. 服务器检查 Origin
    • 若允许该源,返回 Access-Control-Allow-Origin: https://frontend.com(或 * 表示允许所有源)。
    • 若未返回该头,浏览器拦截响应。

示例代码(Node.js):

// 服务器设置响应头
app.get("/data", (req, res) => {
  res.setHeader("Access-Control-Allow-Origin", "https://frontend.com");
  res.json({ data: "CORS allowed" });
});

3. 预检请求的流程

当请求不满足简单请求条件时(如使用 PUT 方法或自定义头),浏览器会先发送预检请求。

3.1 预检请求的触发条件

  • 请求方法为 PUTDELETE 等非简单方法。
  • 使用 Content-Type: application/json 或自定义头(如 X-API-Key)。

3.2 预检请求的步骤

  1. 浏览器发送 OPTIONS 请求,包含以下头:
    • Origin: https://frontend.com
    • Access-Control-Request-Method: PUT(声明实际请求方法)
    • Access-Control-Request-Headers: X-API-Key(声明自定义头)
  2. 服务器响应预检请求,需返回以下头:
    • Access-Control-Allow-Origin: https://frontend.com
    • Access-Control-Allow-Methods: PUT, POST(允许的方法)
    • Access-Control-Allow-Headers: X-API-Key(允许的自定义头)
    • Access-Control-Max-Age: 86400(缓存预检结果,单位秒)
  3. 浏览器检查响应头:若符合要求,发送实际请求;否则报错。

示例代码(Node.js):

// 处理 OPTIONS 预检请求
app.options("/data", (req, res) => {
  res.setHeader("Access-Control-Allow-Origin", "https://frontend.com");
  res.setHeader("Access-Control-Allow-Methods", "PUT, POST");
  res.setHeader("Access-Control-Allow-Headers", "X-API-Key");
  res.setHeader("Access-Control-Max-Age", 86400);
  res.status(204).send(); // 空响应
});

// 处理实际请求
app.put("/data", (req, res) => {
  res.setHeader("Access-Control-Allow-Origin", "https://frontend.com");
  res.json({ status: "Updated" });
});

4. 带凭证的请求

默认情况下,CORS 请求不携带 Cookie 或 HTTP 认证信息。若需传递凭证,需显式配置:

  1. 前端设置:在请求中启用 withCredentials(例如 Fetch API 设置 credentials: "include")。
  2. 服务器响应头
    • Access-Control-Allow-Origin 必须指定具体域名(不能为 *)。
    • 添加 Access-Control-Allow-Credentials: true

示例代码:

// 前端
fetch("https://api.example.com/data", {
  credentials: "include"
});

// 后端
app.get("/data", (req, res) => {
  res.setHeader("Access-Control-Allow-Origin", "https://frontend.com");
  res.setHeader("Access-Control-Allow-Credentials", "true");
  res.json({ user: "authenticated" });
});

5. 常见问题与解决方案

  1. CORS 错误:检查服务器是否返回正确的 Access-Control-Allow-Origin
  2. 凭证被拒绝:确保 Access-Control-Allow-Credentials: true 且域名非通配符。
  3. 预检请求频繁:通过 Access-Control-Max-Age 缓存减少预检次数。

6. 总结

CORS 通过浏览器与服务器的协作,在保障安全的前提下实现跨域资源访问。关键在于理解简单请求与预检请求的区别,并正确配置 HTTP 头。实际应用中,后端框架(如 Express、Spring)通常提供中间件或注解简化 CORS 配置。

跨域资源共享(CORS)的原理与实现 1. 问题描述 跨域资源共享(CORS)是一种机制,允许网页从不同域(协议、域名、端口任一不同)的服务器访问资源。浏览器的同源策略(Same-Origin Policy)默认禁止跨域请求,但实际业务中(如前后端分离架构)常需跨域访问资源,CORS 通过特定 HTTP 头实现安全的跨域通信。 2. CORS 的基本原理 CORS 的核心是 浏览器与服务器通过 HTTP 头协商跨域权限 。整个过程分为两类请求: 简单请求 :直接发送跨域请求,服务器返回 Access-Control-Allow-Origin 头授权。 预检请求 :非简单请求需先发送 OPTIONS 请求,验证通过后再发送实际请求。 2.1 简单请求的条件 满足以下所有条件时,浏览器会将其视为简单请求: 请求方法为 GET 、 POST 或 HEAD 。 请求头仅包含以下字段: Accept 、 Accept-Language 、 Content-Language 、 Content-Type (仅限 application/x-www-form-urlencoded 、 multipart/form-data 、 text/plain )。 未使用自定义头(如 Authorization )或特殊头(如 Range )。 2.2 简单请求的流程 浏览器直接发送跨域请求,并在请求头中自动添加 Origin (例如 Origin: https://frontend.com )。 服务器检查 Origin : 若允许该源,返回 Access-Control-Allow-Origin: https://frontend.com (或 * 表示允许所有源)。 若未返回该头,浏览器拦截响应。 示例代码(Node.js): 3. 预检请求的流程 当请求不满足简单请求条件时(如使用 PUT 方法或自定义头),浏览器会先发送预检请求。 3.1 预检请求的触发条件 请求方法为 PUT 、 DELETE 等非简单方法。 使用 Content-Type: application/json 或自定义头(如 X-API-Key )。 3.2 预检请求的步骤 浏览器发送 OPTIONS 请求 ,包含以下头: Origin: https://frontend.com Access-Control-Request-Method: PUT (声明实际请求方法) Access-Control-Request-Headers: X-API-Key (声明自定义头) 服务器响应预检请求 ,需返回以下头: Access-Control-Allow-Origin: https://frontend.com Access-Control-Allow-Methods: PUT, POST (允许的方法) Access-Control-Allow-Headers: X-API-Key (允许的自定义头) Access-Control-Max-Age: 86400 (缓存预检结果,单位秒) 浏览器检查响应头 :若符合要求,发送实际请求;否则报错。 示例代码(Node.js): 4. 带凭证的请求 默认情况下,CORS 请求不携带 Cookie 或 HTTP 认证信息。若需传递凭证,需显式配置: 前端设置 :在请求中启用 withCredentials (例如 Fetch API 设置 credentials: "include" )。 服务器响应头 : Access-Control-Allow-Origin 必须指定具体域名(不能为 * )。 添加 Access-Control-Allow-Credentials: true 。 示例代码: 5. 常见问题与解决方案 CORS 错误 :检查服务器是否返回正确的 Access-Control-Allow-Origin 。 凭证被拒绝 :确保 Access-Control-Allow-Credentials: true 且域名非通配符。 预检请求频繁 :通过 Access-Control-Max-Age 缓存减少预检次数。 6. 总结 CORS 通过浏览器与服务器的协作,在保障安全的前提下实现跨域资源访问。关键在于理解简单请求与预检请求的区别,并正确配置 HTTP 头。实际应用中,后端框架(如 Express、Spring)通常提供中间件或注解简化 CORS 配置。