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

React应用中使用Firebase Functions onCall方法调用createSetupIntent时的CORS错误解决方法

React应用中使用Firebase Functions onCall方法调用createSetupIntent时的CORS错误解决方法

看起来你已经做了不少正确的操作——替换了直接fetch调用、用了httpsCallable、确认函数是onCall类型,但还是遇到了CORS问题,这种情况我之前也碰到过,大概率是某个容易忽略的小细节导致的,咱们一步步排查:

1. 彻底排查代码中是否存在遗留的直接HTTP调用

你说已经替换了所有fetch/postJSON,但还是要再仔细检查一遍:

  • 全局搜索项目中所有包含createSetupIntent的文件,看看有没有漏掉的直接fetch('https://us-central1-lurk-*.cloudfunctions.net/createSetupIntent')或者用axios等工具的POST请求。
  • 重点检查你代码里提到的StripeCardForm组件,这个组件会不会在处理卡片验证时,不小心直接调用了函数URL?
  • 检查项目中的工具函数(比如封装的API请求文件),有没有遗留的旧调用逻辑。

2. 移除onCall函数中多余的CORS中间件

你的getPaymentMethods函数里加了CORS中间件,这是完全没必要的——https.onCall类型的函数,Firebase SDK会自动处理跨域请求的CORS头,手动添加CORS中间件反而会干扰Firebase的默认处理逻辑,导致预请求失败。

修改getPaymentMethods的代码,删掉所有CORS相关的代码,改成这样:

exports.getPaymentMethods = functions.https.onCall(async (data, context) => {
  try {
    if (!context.auth) {
      throw new functions.https.HttpsError('unauthenticated', 'Must be logged in');
    }

    console.log('Getting payment methods for user:', context.auth.uid);

    const userDoc = await admin.firestore().collection('userInfo').doc(context.auth.uid).get();

    if (!userDoc.exists) {
      console.log('User document not found, creating new document');
      await admin.firestore().collection('userInfo').doc(context.auth.uid).set({
        email: context.auth.token.email,
        createdAt: admin.firestore.FieldValue.serverTimestamp()
      });
    }

    const userData = userDoc.exists ? userDoc.data() : {};
    let customerId = userData.stripeCustomerId;

    if (!customerId) {
      console.log('No customer ID found, creating new customer');
      const customer = await stripe.customers.create({
        email: context.auth.token.email,
        metadata: {
          firebaseUID: context.auth.uid
        }
      });
      customerId = customer.id;
      console.log('Created new customer:', customerId);

      // Save the customer ID to Firestore
      await admin.firestore().collection('userInfo').doc(context.auth.uid).update({
        stripeCustomerId: customerId
      });
    } else {
      console.log('Found existing customer:', customerId);
    }

    // Get payment methods
    const paymentMethods = await stripe.paymentMethods.list({
      customer: customerId,
      type: 'card'
    });

    console.log('Found payment methods:', paymentMethods.data.length);

    return {
      paymentMethods: paymentMethods.data,
      customerId: customerId
    };
  } catch (error) {
    console.error('Error in getPaymentMethods:', error);
    throw new functions.https.HttpsError('internal', error.message);
  }
});

修改完成后,重新部署你的Firebase Functions:

firebase deploy --only functions

3. 确认Firebase客户端的Functions实例初始化正确

如果你的Functions部署在us-central1区域,客户端初始化时一定要明确指定区域,否则SDK可能会尝试用默认区域(如果和部署区域不匹配,会导致请求方式异常,触发CORS):

修改你的../firebase文件中的Functions初始化代码:

import { initializeApp } from "firebase/app";
import { getFunctions } from "firebase/functions";

const firebaseConfig = {
  // 你的配置
};

const app = initializeApp(firebaseConfig);
// 明确指定函数部署的区域
const functions = getFunctions(app, "us-central1");

export { functions };

4. 本地开发环境的特殊检查

如果你是在本地http://localhost:5173开发:

  • 确保没有混用生产环境的函数和本地模拟器。如果用本地模拟器,要加上连接代码:
    import { connectFunctionsEmulator } from "firebase/functions";
    
    if (process.env.NODE_ENV === "development") {
      connectFunctionsEmulator(functions, "localhost", 5001);
    }
    
  • 清除浏览器缓存或者用隐身窗口测试,避免旧的请求缓存导致的异常。

5. 验证Firebase Functions的类型

登录Firebase控制台,进入Functions页面,确认createSetupIntent和getPaymentMethods的类型是Callable,而不是HTTP。如果是HTTP类型,说明部署时出了问题,重新部署函数即可。

按照这些步骤排查后,应该就能解决CORS问题了。本质上,https.onCall + httpsCallable的组合是不需要手动处理CORS的,出现问题大概率是代码中有遗留的直接调用,或者客户端/服务端的配置不匹配。

备注:内容来源于stack exchange,提问作者A User

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 14:29:51