reactjs - 如何在 React 和 Firebase 中使用 Stripe
问题描述
所以我使用 firebase 作为我的数据库和托管服务,并且我已经在 React 中编写了应用程序。
现在我正在尝试将 Stripe 添加到应用程序中,以便向客户收费。但是有一个问题,Stripe 似乎需要一个单独的服务器,这有点问题,因为我使用的是 Firebase。
我已阅读文档(此处 - https://firebase.google.com/docs/use-cases/payments)并观看了来自 firebase 的视频(此处 - https://www.youtube.com/watch?v= BrLTF4QdRrM和这里 - https://www.youtube.com/watch?v=BrLTF4QdRrM)我仍然迷路了。
我不知道我应该在哪里包含 Stripe Publishable Key,而且我已经陷入了这样的困境,我将不得不花费接下来的几个小时来撤销最后几个小时的努力。
如果您可以向我指出一个简单指南的方向,或者只是告诉我可发布密钥需要去哪里,那将非常有帮助!
这可能不仅仅是帮助,但这是我创建的用于创建条带客户和条带费用等的代码。
mport * as stripe from "stripe";
import * as functions from "firebase";
import getFirestoreDb from "../firebase/firestore/getFirestoreDb";
// import {firestore} from "@firebase/firestore/dist/packages/firestore/test/util/api_helpers";
// const admin = require('firebase-admin');
// admin.initializeApp();
// const logging = require('@google-cloud/logging')();
// const currency = functions.config().stripe.currency || 'USD';
const db = getFirestoreDb();
//START CUSTOMER CHARGE //
// Charge the Stripe customer whenever an amount is created in Cloud Firestore
export const createStripeCharge = functions.firestore
.document('stripe_customers/{userId}/charges/{autoId}')
.onCreate(async ( snap, context) => {
const val = snap.data();
try {
//Look up the Stripe customer id written in createStripeCustomer
const snapshot = await
db.collection('stripe_customers')
.doc(context.params.userId).get();
const snapval = snapshot.data();
const customer = snapval.customer_id;
// Create a charge using the pushId as the idempotency key
// protecting against double charges
const amount = val.amount;
const idempotencyKey = context.params.id;
const currency = "USD";
const charge = {amount, currency, customer};
if (val.source !== null) {
charge.source = val.source;
}
// setSourceOrDefault(charge, snap.data().source)
const response = await stripe.charges.create(charge, {idempotency_key: idempotencyKey} );
//if the result is successful, write it back to the database
return snap.ref.set(response, {merge:true});
} catch(error) {
// We want to capture errors and render them in a user-friendly way, while
// still logging an exception with StackDriver
await snap.ref.set({error: userFacingMessage(error)}, {merge:true});
// return reportError(error, {user: context.params.userId});
}
});
// END CUSTOMER CHARGE //
// When a user is created, register them with Stripe
export const createStripeCustomer = functions.auth.user().onCreate(async (user) => {
const customer = await stripe.customers.create({email: user.email});
return db.collection('stripe_customers').doc(user.uid).set({customer_id: customer.id});
});
// Add a payment source (card) for a user by writing a stripe payment source token to Cloud Firestore
export const addPaymentSource = functions.firestore.document('/stripe_customers/{userId}/tokens/{pushId}').onCreate(async (snap, context) => {
const source = snap.data();
const token = source.token;
if (source === null){
return null;
}
try {
const snapshot = await db.collection('stripe_customers').doc(context.params.userId).get();
const customer = snapshot.data().customer_id;
const response = await stripe.customers.createSource(customer, {source: token});
return db.collection('stripe_customers').doc(context.params.userId).collection("sources").doc(response.fingerprint).set(response, {merge: true});
} catch (error) {
await snap.ref.set({'error':userFacingMessage(error)},{merge:true});
// return reportError(error, {user: context.params.userId});
}
});
// When a user deletes their account, clean up after them
export const cleanupUser = functions.auth.user().onDelete(async (user) => {
const snapshot = await db.collection('stripe_customers').doc(user.uid).get();
const customer = snapshot.data();
await stripe.customers.del(customer.customer_id);
return db.collection('stripe_customers').doc(user.uid).delete();
});
// To keep on top of errors, we should raise a verbose error report with Stackdriver rather
// than simply relying on console.error. This will calculate users affected + send you email
// alerts, if you've opted into receiving them.
// // [START reporterror]
// function reportError(err, context = {}) {
// // This is the name of the StackDriver log stream that will receive the log
// // entry. This name can be any valid log stream name, but must contain "err"
// // in order for the error to be picked up by StackDriver Error Reporting.
// const logName = 'errors';
// const log = logging.log(logName);
//
// // https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/MonitoredResource
// const metadata = {
// resource: {
// type: 'cloud_function',
// labels: {function_name: process.env.FUNCTION_NAME},
// },
// };
//
// // https://cloud.google.com/error-reporting/reference/rest/v1beta1/ErrorEvent
// const errorEvent = {
// message: err.stack,
// serviceContext: {
// service: process.env.FUNCTION_NAME,
// resourceType: 'cloud_function',
// },
// context: context,
// };
//
// // Write the error log entry
// return new Promise((resolve, reject) => {
// log.write(log.entry(metadata, errorEvent), (error) => {
// if (error) {
// return reject(error);
// }
// return resolve();
// });
// });
// }
// [END report error]
function userFacingMessage(error) {
return error.type ? error.message : 'An error has occurred, developers have been alerted';
}
stripe.setPublishableKey("STRIPE_KEY");
解决方案
您必须在客户端设置可发布密钥。
例如,使用 React Native 和tipsi-stripe (stripe client sdk),你可以这样做:
import stripe from 'tipsi-stripe'
stripe.setOptions({
publishableKey: 'YOUR-PUBLISHABLE-KEY',
})
您只需要使用您的可发布密钥初始化您正在使用的条带客户端 sdk。
推荐阅读
- kubernetes - Error in image_pull_secrets for private repository Airflow deployed in Kubernetes
- python - Get differences of two list that contain different object types using python
- r - Can't query VIEW in BigQuery with dbplyr
- javascript - Determine inner browser y-position in javascript
- python - Merging two dataframes with different encoding?
- parsing - Using superpower to parse simple block oriented data structures
- powershell - Powershell: view remote computer current user certificate
- python - Why can a parent send data only once in a bidirectional channel?
- c++ - How to maintaining relative order of non-zero elements during array sorting?
- cypress - Cypress test always fails in GitHub Actions & headless, but not locally in normal mode?