Как исправить ошибку CORS функций Firebase для PaymentMethodManager в моем приложении React?Javascript

Форум по Javascript
Ответить
Anonymous
 Как исправить ошибку CORS функций Firebase для PaymentMethodManager в моем приложении React?

Сообщение Anonymous »

У меня есть приложение React с платежами Stripe. Я хочу, чтобы пользователи могли просматривать, добавлять, редактировать и удалять свои способы оплаты на вкладке «Платежи» в настройках. Для этого мой интерфейс вызывает облачную функцию Firebase с именем createSetupIntent. Однако всякий раз, когда я нажимаю кнопку, чтобы создать намерение установки, я получаю следующую ошибку CORS в консоли браузера:
Доступ к выборке по адресу «https://us-central1-lurk-.cloudfunctions.net/createSetupIntent» из источника «http://localhost:5173» заблокирован политикой CORS:
Ответ на предполетный запрос не проходит проверку контроля доступа:
Нет Заголовок Access-Control-Allow-Origin присутствует в запрошенном ресурсе.
и запрос завершается с ошибкой:
POST https://us-central1-lurk-.cloudfunctions.net/createSetupIntent net: :ERR_FAILED
Похоже, я все еще выполняю где-то прямую выборку, которая запускает предварительную проверку CORS. Как настроить или исправить вызовы, чтобы я мог правильно использовать метод onCall Firebase Functions (httpsCallable), не сталкиваясь с этими ошибками CORS?
Я заменил все вызовы выборки или пользовательские postJSON на httpsCallable из Firebase SDK в PaymentMethodManager.jsx.
Я проверил свой код функций Firebase (в createSetupIntent), чтобы убедиться, что он экспортируется как функции.https.onCall, поэтому он должен обходить типичный CORS, если я использую httpsCallable.
Я добавил промежуточное программное обеспечение cors(...) в некоторые файлы функций, чтобы разрешить origin: true, но я понял, что функциям onCall это может не понадобиться, если я использую только httpsCallable.
Я обязательно повторно развернул свои функции.
Я проверил правильность импорта :
импортировать { httpsCallable } from 'firebase/functions';
const createSetupIntentFn = httpsCallable(functions, 'createSetupIntent');
Однако ошибка предполагает, что функция все еще вызывается через прямой POST на cloudfunctions.net вместо обычного конвейера httpsCallable.
Я хочу, чтобы все ссылки на createSetupIntent выполнялись через httpsCallable и не остается никаких вызовов прямой выборки.
PaymentMethodManager.jsx

Код: Выделить всё

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 && }

);
};
createSetupIntent (из моего Stripe.js)

Код: Выделить всё

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);
}
});
getPaymentMethods (из моего Stripe.js)

Код: Выделить всё

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);
}
});
Однако, несмотря на использование httpsCallable, на вкладке «Сеть» моих инструментов разработчика отображается POST для …cloudfunctions.net/createSetupIntent с предварительным запросом OPTIONS, который завершается с ошибкой «No 'Access-Control-Allow- Сообщение «Заголовок источника». Я подозреваю, что где-то в моем коде все еще остался вызов прямого извлечения или неправильная конфигурация в настройке функций Firebase.
Я был бы признателен за любые рекомендации по определению оставшегося прямого вызова или правильной настройке моей функции/кора onCall, чтобы запрос больше не терпит неудачу. Моя цель — создать полнофункциональный PaymentMethodManager, в котором будут перечислены текущие способы оплаты и позволяющий добавлять новые без каких-либо проблем с CORS.
Любая помощь будет принята с благодарностью!

Подробнее здесь: https://stackoverflow.com/questions/793 ... n-my-react
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»