Wie behebe ich den CORS-Fehler von Firebase Functions für PaymentMethodManager in meiner React-App?
Posted: 19 Jan 2025, 20:38
Ich habe eine React-Anwendung mit Stripe-Zahlungen. Ich möchte, dass Benutzer auf der Registerkarte „Zahlungen“ in den Einstellungen ihre Zahlungsmethoden anzeigen, hinzufügen, bearbeiten und entfernen können. Um dies zu erreichen, ruft mein Frontend eine Firebase Cloud-Funktion mit dem Namen „createSetupIntent“ auf. Wenn ich jedoch auf die Schaltfläche klicke, um eine Setup-Absicht zu erstellen, wird in der Browserkonsole der folgende CORS-Fehler angezeigt:
Zugriff zum Abrufen unter „https:/“ /us-central1-lurk-.cloudfunctions.net/createSetupIntent' vom Ursprung 'http://localhost:5173' wurde durch die CORS-Richtlinie blockiert:
Antwort auf Preflight-Anfrage nicht Zugangskontrolle passieren Überprüfen Sie:
Auf der angeforderten Ressource ist kein Header „Access-Control-Allow-Origin“ vorhanden.
Und die Anfrage schlägt fehl mit:< /p>
Ich scheine immer noch irgendwo einen direkten Abruf durchzuführen, der einen CORS-Preflight auslöst. Wie konfiguriere oder behebe ich die Aufrufe, damit ich die Firebase Functions-onCall-Methode (httpsCallable) ordnungsgemäß verwenden kann, ohne auf diese CORS-Fehler zu stoßen?
Ich habe alle Abruf- oder benutzerdefinierten PostJSON-Aufrufe durch httpsCallable von ersetzt das Firebase SDK in PaymentMethodManager.jsx.
Ich habe meinen Firebase Functions-Code (in createSetupIntent) überprüft, um sicherzustellen, dass er exportiert wird als Functions.https.onCall, daher sollte es das typische CORS umgehen, wenn ich httpsCallable verwende.
Ich habe in einigen Funktionsdateien cors(...)-Middleware hinzugefügt, um „origin: true“ zu ermöglichen, aber ich Mir wurde klar, dass onCall-Funktionen dies möglicherweise nicht benötigen, wenn ich nur httpsCallable verwende.
Ich habe darauf geachtet, meine Funktionen erneut bereitzustellen.
Ich habe überprüft, dass meine Importe korrekt sind :
Der Fehler deutet jedoch darauf hin, dass die Funktion immer noch über einen direkten POST an cloudfunctions.net aufgerufen wird, anstatt die normale httpsCallable-Pipeline zu durchlaufen.
I Ich möchte sicherstellen, dass alle Verweise auf createSetupIntent über httpsCallable erfolgen und keine direkten Abrufaufrufe verbleiben.
PaymentMethodManager.jsx
createSetupIntent (aus meinem Stripe.js)
getPaymentMethods (von meinem Stripe.js)
Trotz der Verwendung von httpsCallable zeigt die Registerkarte „Netzwerk“ meiner Entwicklertools jedoch einen POST an …cloudfunctions.net/createSetupIntent mit einer Preflight-OPTIONS-Anfrage an, die mit der Fehlermeldung „Keine Zugriffskontrolle-Zulassen-“ fehlschlägt. „Origin'-Header“-Meldung. Ich vermute, dass irgendwo in meinem Code immer noch ein direkter Abrufaufruf übrig ist oder eine Fehlkonfiguration im Firebase Functions-Setup vorliegt.
Ich suche nach Anleitung, wie ich den verbleibenden Direktaufruf lokalisieren oder meine onCall-Funktion richtig konfigurieren kann /cors, damit die Anfrage nicht mehr fehlschlägt. Mein Ziel ist es, einen voll funktionsfähigen PaymentMethodManager zu haben, der aktuelle Zahlungsmethoden auflistet und das Hinzufügen neuer Zahlungsmethoden ohne CORS-Probleme ermöglicht.
Zugriff zum Abrufen unter „https:/“ /us-central1-lurk-.cloudfunctions.net/createSetupIntent' vom Ursprung 'http://localhost:5173' wurde durch die CORS-Richtlinie blockiert:
Antwort auf Preflight-Anfrage nicht Zugangskontrolle passieren Überprüfen Sie:
Auf der angeforderten Ressource ist kein Header „Access-Control-Allow-Origin“ vorhanden.
Und die Anfrage schlägt fehl mit:< /p>
Code: Select all
POST https://us-central1-lurk-.cloudfunctions.net/createSetupIntent net::ERR_FAILED
Ich habe alle Abruf- oder benutzerdefinierten PostJSON-Aufrufe durch httpsCallable von ersetzt das Firebase SDK in PaymentMethodManager.jsx.
Ich habe meinen Firebase Functions-Code (in createSetupIntent) überprüft, um sicherzustellen, dass er exportiert wird als Functions.https.onCall, daher sollte es das typische CORS umgehen, wenn ich httpsCallable verwende.
Ich habe in einigen Funktionsdateien cors(...)-Middleware hinzugefügt, um „origin: true“ zu ermöglichen, aber ich Mir wurde klar, dass onCall-Funktionen dies möglicherweise nicht benötigen, wenn ich nur httpsCallable verwende.
Ich habe darauf geachtet, meine Funktionen erneut bereitzustellen.
Ich habe überprüft, dass meine Importe korrekt sind :
Code: Select all
import { httpsCallable } from 'firebase/functions';
const createSetupIntentFn = httpsCallable(functions, 'createSetupIntent');
I Ich möchte sicherstellen, dass alle Verweise auf createSetupIntent über httpsCallable erfolgen und keine direkten Abrufaufrufe verbleiben.
PaymentMethodManager.jsx
Code: Select all
import React, { useState } from 'react';
import { functions } from '../firebase';
import { httpsCallable } from 'firebase/functions';
import { useToast } from '@chakra-ui/react';
export const PaymentMethodManager = () => {
const [showAddCard, setShowAddCard] = useState(false);
const toast = useToast();
const handleAddPaymentMethod = async () => {
try {
// Attempt to create a setup intent via httpsCallable
const createSetupIntentFn = httpsCallable(functions, 'createSetupIntent');
const { data } = await createSetupIntentFn();
if (!data || !data.clientSecret) {
throw new Error('Missing client secret from createSetupIntent response');
}
// Use data.clientSecret with Stripe.js to confirm a card setup
console.log('Setup Intent created:', data.clientSecret);
} catch (error) {
console.error('Error creating setup intent:', error);
toast({
title: 'Error',
description: error.message,
status: 'error',
duration: 3000,
});
}
};
return (
Add Payment Method
{showAddCard && }
);
};
Code: Select all
exports.createSetupIntent = functions.https.onCall(async (data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError('unauthenticated', 'Must be logged in');
}
try {
console.log('Creating setup intent for user:', context.auth.uid);
// Get user's Stripe customer ID from Firestore
const userDoc = await admin.firestore().collection('userInfo').doc(context.auth.uid).get();
const userData = userDoc.exists ? userDoc.data() : {};
let customerId = userData.stripeCustomerId;
// If no customer ID exists, create a new customer
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).set({
stripeCustomerId: customerId,
email: context.auth.token.email,
updatedAt: admin.firestore.FieldValue.serverTimestamp()
}, { merge: true });
} else {
console.log('Found existing customer:', customerId);
}
// Create a setup intent for the customer
const setupIntent = await stripe.setupIntents.create({
customer: customerId,
payment_method_types: ['card'],
usage: 'off_session',
metadata: {
firebaseUID: context.auth.uid,
customerId: customerId
}
});
console.log('Created setup intent:', setupIntent.id);
return {
clientSecret: setupIntent.client_secret,
customerId: customerId
};
} catch (error) {
console.error('Error in createSetupIntent:', error);
throw new functions.https.HttpsError('internal', error.message);
}
});
Code: Select all
exports.getPaymentMethods = functions.https.onCall(async (data, context) => {
// Add CORS headers if needed
const corsMiddleware = (req, res) => new Promise((resolve, reject) => {
cors(req, res, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
try {
if (context.rawRequest && context.rawResponse) {
await corsMiddleware(context.rawRequest, context.rawResponse);
}
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);
}
});
Ich suche nach Anleitung, wie ich den verbleibenden Direktaufruf lokalisieren oder meine onCall-Funktion richtig konfigurieren kann /cors, damit die Anfrage nicht mehr fehlschlägt. Mein Ziel ist es, einen voll funktionsfähigen PaymentMethodManager zu haben, der aktuelle Zahlungsmethoden auflistet und das Hinzufügen neuer Zahlungsmethoden ohne CORS-Probleme ermöglicht.