除了 `Access-Control-Allow-Origin`,服务器通常还需要设置那些关键响应头?

除了 Access-Control-Allow-Origin,服务器通常还需要设置以下关键响应头来完整支持CORS:


必需头

  1. Access-Control-Allow-Methods

    • 定义允许的HTTP方法(如 GET, POST, PUT, DELETE, OPTIONS)。
    • 示例:Access-Control-Allow-Methods: GET, POST, OPTIONS
  2. Access-Control-Allow-Headers

    • 声明允许客户端携带的请求头(如 Content-Type, Authorization)。
    • 示例:Access-Control-Allow-Headers: Content-Type, X-API-Key
  3. Access-Control-Allow-Credentials(可选)

    • 若需传递Cookie或认证信息,需设置为 true
    • 注意:此时 Access-Control-Allow-Origin 不能为通配符 *

预检请求优化头

  1. Access-Control-Max-Age
    • 指定预检请求(OPTIONS)结果的缓存时间(秒),减少重复预检。
    • 示例:Access-Control-Max-Age: 86400(缓存24小时)

高级控制头

  1. Access-Control-Expose-Headers

    • 允许客户端访问的额外响应头(默认仅暴露基础头如 Cache-ControlContent-Language)。
    • 示例:Access-Control-Expose-Headers: X-Total-Count
  2. Vary: Origin

    • 提示缓存服务器根据 Origin 请求头返回不同内容,避免缓存污染。

完整示例场景

简单请求(如GET/POST且无自定义头):

Access-Control-Allow-Origin: https://example.com

复杂请求(含预检OPTIONS):

预检响应头:

Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 3600

实际请求响应头:

Access-Control-Allow-Origin: https://example.com
Access-Control-Expose-Headers: X-Data-Version
Access-Control-Allow-Credentials: true
Vary: Origin

注意事项

  • 若允许任意源访问,可使用 Access-Control-Allow-Origin: *,但与凭证模式互斥
  • 生产环境建议严格限定允许的源、方法、头字段,避免安全风险。
  • 对于携带认证信息的请求,需显式设置 Access-Control-Allow-Credentials: true

通过组合这些头部,可灵活控制跨域资源的安全共享策略。

如果Access-Control-Allow-Origin:需要配置多个源呢?

如果需要在 Access-Control-Allow-Origin 中配置多个源,标准的HTTP规范不允许直接设置多个域名(如 Access-Control-Allow-Origin: https://a.com, https://b.com 是无效的)。但可以通过以下方案实现多源支持:


方案1:动态匹配请求源(推荐)

在服务器端根据请求头中的 Origin 值动态返回允许的源。
实现逻辑:

  1. 读取客户端请求的 Origin 头。
  2. 检查该 Origin 是否在预配置的白名单中。
  3. 如果在白名单内,则设置 Access-Control-Allow-Origin: [该Origin值];否则拒绝或返回错误。

代码示例(Node.js/Express):

const allowedOrigins = [
  'https://example.com',
  'https://app.example.com',
  'http://localhost:3000'
];

app.use((req, res, next) => {
  const origin = req.headers.origin;
  if (allowedOrigins.includes(origin)) {
    res.header('Access-Control-Allow-Origin', origin); // 动态设置匹配的源
    res.header('Access-Control-Allow-Credentials', 'true'); // 如需凭证
  }
  res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  next();
});

方案2:条件性返回通配符(限制场景)

若允许的源较多且无需凭证(Cookie/Auth),可对特定条件返回通配符 *

// 仅当请求源为信任的测试环境时返回 *
if (allowedOrigins.includes(origin) && origin.includes('test-env')) {
  res.header('Access-Control-Allow-Origin', '*');
} else {
  res.header('Access-Control-Allow-Origin', origin);
}

注意:通配符 *Access-Control-Allow-Credentials: true 互斥!


方案3:Vary头避免缓存污染

动态设置 Access-Control-Allow-Origin 时,必须添加 Vary: Origin 响应头,确保缓存服务器根据不同 Origin 分别缓存响应:

Access-Control-Allow-Origin: https://example.com
Vary: Origin

否则可能导致缓存将A源的响应返回给B源,引发安全问题。


方案4:Nginx层配置

在Nginx中通过 map 指令实现动态源匹配:

map $http_origin $cors_origin {
    default "";
    ~^https?://(example\.com|app\.example\.com)$ $http_origin;
}

server {
    location /api {
        if ($cors_origin) {
            add_header Access-Control-Allow-Origin $cors_origin;
            add_header Vary Origin;
        }
        # 其他CORS头...
    }
}

注意事项

  1. 凭证模式限制:若需 Access-Control-Allow-Credentials: true,则必须动态指定具体源(不能为 *)。
  2. 安全性:严格校验白名单,避免反射型设置(如直接返回 req.headers.origin 而不校验)。
  3. 性能:频繁的OPTIONS预检请求可通过 Access-Control-Max-Age 缓存优化。

通过以上方案,可灵活支持多源跨域访问需求。

posted @ 2026-02-05 15:01  龙陌  阅读(22)  评论(0)    收藏  举报