You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular HttpClient中带withCredentials:true和body请求为何触发CORS错误?

解决带请求体的POST请求触发CORS预检错误,无法设置Cookie

问题核心

带请求体的POST请求会触发浏览器的OPTIONS预检请求,当前Cloud Function的CORS配置存在两个关键问题,导致预检不通过:

  1. Access-Control-Allow-Methods仅允许GET方法,但实际请求是POST,预检请求会验证是否允许该方法;
  2. 当请求Origin不在允许列表且非模拟器环境时,Access-Control-Allow-Origin未被设置,此时即使设置了Access-Control-Allow-Credentials: true,浏览器也会判定该头无效(带凭证的CORS请求要求Access-Control-Allow-Origin必须是具体的Origin,不能为空或通配符)。

修正后的Cloud Function代码

/* eslint-disable max-len */
import {onRequest} from "firebase-functions/v2/https";
import {CookieOptions, Request, Response} from "express";

export const setCookie = onRequest((req, res) => {
  handleCors(req, res);
  // 预检OPTIONS请求已在handleCors处理,直接结束
  if (req.method === "OPTIONS") {
    return;
  }
  
  const sessionCookie = (Math.random()* 100000000000000000).toString();
  const expiresIn = 60 * 60 * 24 * 5 * 1000;
  const options: CookieOptions = {
    maxAge: expiresIn,
    httpOnly: true,
    // 仅生产环境启用secure,本地模拟器http环境下关闭,否则浏览器不存储Cookie
    secure: process.env.NODE_ENV === 'production',
    sameSite: "none",
  };
  res.cookie("_rememberme", sessionCookie, options);
  res.send({data: "Set Cookie"});
});

const handleCors = (req: Request, res: Response) => {
  const origin = req.get("origin") ?? "";
  let allowedOrigin = "";

  const allowedOrigins = ["https://account.topoint.org", "https://experiences.topoint.org", "https://checkout.topoint.org", "http://localhost:4200"];
  // 本地模拟器环境直接允许请求Origin
  if (process.env.FUNCTIONS_EMULATOR) {
    allowedOrigin = origin;
  } else if (allowedOrigins.includes(origin)) {
    allowedOrigin = origin;
  }

  // 仅合法Origin才设置CORS头
  if (allowedOrigin) {
    res.set("Access-Control-Allow-Origin", allowedOrigin);
    res.set("Access-Control-Allow-Credentials", "true");
  }

  if (req.method === "OPTIONS") {
    // 允许实际请求使用的POST方法,保留GET
    res.set("Access-Control-Allow-Methods", "GET, POST");
    res.set("Access-Control-Allow-Headers", "Authorization, Content-Type");
    res.set("Access-Control-Max-Age", "3600");
    res.status(204).send("");
  }
};

关键修改说明

  • 匹配请求方法:将Access-Control-Allow-Methods改为GET, POST,覆盖实际使用的POST请求;
  • 优化Origin校验:统一处理模拟器和生产环境的Origin,确保只有合法来源才会设置CORS头,避免空值导致凭证头失效;
  • 适配本地环境:生产环境才启用secure: true,本地HTTP环境下关闭,否则浏览器会拒绝存储Secure Cookie;
  • 提前终止预检请求:在主函数中判断OPTIONS请求,避免执行后续Cookie设置逻辑。

Angular代码无需修改,保持withCredentials: true配置即可。

内容的提问来源于stack exchange,提问作者Jason Rich Darmawan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 22:19:53