【问题标题】:Update user state in database after HTTP cloud function is fired - stripe checkout触发 HTTP 云功能后更新数据库中的用户状态 - 条带结帐
【发布时间】:2020-11-01 07:00:19
【问题描述】:

我将用户存储在 firebase 实时数据库和条带中以处理付款。经过身份验证的用户可以单击一个按钮,并将被重定向到 Stripe Checkout。付款后,用户会被重定向到应用程序中的success_url。接下来我想更新数据库中的用户对象 - 只需保存支付成功的信息及其 id。

问题:重定向到success_url后,我不知道如何找到完成付款的用户。我想在付款后更新数据库中的用户数据。

想法:我可以将payment_intent 保存在用户配置文件中,因为此信息通过会话发送到客户端。然后,付款完成后,我可以搜索payment_intent 并更新拥有此数据的用户。但这是一个好方法吗?有没有更好的方法找到用户?

我的代码基于 Firebase Cloud Function HTTP 请求。 在 Stripe guidelines 接受付款之后,我为想要付款的用户创建了一个会话:

export const payment = functions.https.onRequest((request, response) => {
  cors(request, response, async () => {
    response.set("Access-Control-Allow-Headers", "Content-Type");
    response.set("Access-Control-Allow-Credentials", "true");
    response.set("Access-Control-Allow-Origin", "*");
    await stripe.checkout.sessions.create(
      {
        payment_method_types: ["card"],
        line_items: [
          {
            price_data: {
              currency: "usd",
              product_data: {
                name: "Test"
              },
              unit_amount: 1000
            },
            quantity: 1
          }
        ],
        mode: "payment",
        success_url: "https://example.com/success",
        cancel_url: "https://example.com/cancel"
      },
      function(err: Error, session: any) {
        response.send(session); 
        // the session is sent to the client and can be used to finalise a transaction
      }
    );
  });
});

在客户端,我使用 axios 调用 payment 云函数请求,然后将 sessionId 传递给 Stripe.redirectToCheckout,这将启动结帐重定向:

let sessionId = "";
await axios.post("payment function url request")
    .then(response => {
        sessionId = response.data.id;
    });
const stripe: any = await loadStripe("stripe key");
stripe.redirectToCheckout({
    sessionId: sessionId
});

客户在 Stripe Checkout 上完成付款后,会被重定向到指定为 success_url 的 URL,建议在结帐完成时从 stripe 运行 webhook。 它允许触发另一个云功能,该功能向客户端发送有关付款成功的响应response.json({ received: true })

export const successfulPayment = functions.https.onRequest(
  (request, response) => {
    const sig = request.headers["stripe-signature"];
    let event;

    try {
      event = stripe.webhooks.constructEvent(
        request.rawBody,
        sig,
        endpointSecret
      );
    } catch (err) {
      return response.status(400).send(`Webhook Error: ${err.message}`);
    }
    // Handle the checkout.session.completed event
    // Should I update the user data in the database here?
    if (event.type === "checkout.session.completed") {
      const session = event.data.object;
      console.log(`Event passed: ${session}`);
    }
    // Return a response to acknowledge receipt of the event
    response.json({ received: true });
    // Or how do I use this response to then update the user from the client side?
  }
);

我将非常感谢所有的帮助和建议 :)

【问题讨论】:

    标签: javascript firebase firebase-realtime-database stripe-payments


    【解决方案1】:

    谢谢你的问题,卡布!

    接下来我想更新数据库中的用户对象 - 只需保存支付成功的信息及其 id。

    首先,您可能不希望将成功 URL 用作存储成功付款的信号。有可能客户关闭了浏览器,您的服务器与客户之间的互联网连接中断,或者客户在成功付款后点击成功 URL 之前就离开了。相反,强烈建议使用 webhook,特别是监听 checkout.session.completed 事件。从成功 URL 中,您可以检索结帐会话并向客户显示状态(如果他们到达那里),但您不希望将其用于履行或作为付款状态的真实来源。

    我可以将 payment_intent 保存在用户配置文件中,因为此信息通过会话发送到客户端。然后,在付款完成后,我可以搜索 payment_intent 并更新拥有此数据的用户。但这是一个好方法吗?有没有更好的方法找到用户?

    我相信您的意思是 Checkout Session ID,而不是 PaymentIntent ID。直到用户被重定向后才会创建 PaymentIntent ID。是的,这是一个好主意和一个好习惯,可以在您的数据库中的某处存储对 Checkout Session 的 ID 的引用以及用户配置文件。您还可以在创建 Checkout Session 时设置metadata 值,并参考系统中的用户 ID。这样,当您收到checkout.session.completed webhook 事件时,您可以根据存储在metadata 中的 ID 按 ID 查找用户,或者根据前面讨论的用户配置文件中存储的 Checkout Session 的 ID 查找用户。

    建议在结帐完成时从条带运行 webhook。它允许触发另一个云函数,该函数向客户端发送关于成功支付的响应 response.json({ received: true })

    请注意,webhook 事件是从 Stripe 的服务器直接发送到您的服务器的 POST 请求。它不会以任何方式呈现或将响应发送回客户的浏览器或客户端。来自服务器的 webhook 响应返回到 Stripe,并且这三方之间没有共享会话的概念。当作为 webhook 处理程序的结果发送 response.json({ received: true }) 时,它被发送回 Stripe,而不是客户的浏览器。

    【讨论】:

    • 感谢您的详细回答和所有更正。我刚从 Stripe 开始,这就是为什么我可能在这里搞砸了一些概念。带有 paymentIntent ID 的东西:创建成功的付款后,它会记录在我的条纹仪表板/付款中,并且其描述中的每笔付款都包含该 paymentIntent ID。这就是为什么我认为存储它以便与存储在 db 上的 ID 进行比较至关重要。但是最好保存会话ID?
    • 我目前的想法是我将 ID 存储为具有值的键,例如:"IoGuaNqlfQs1xL4qVM": "incomplete" 在完成付款之前或succeeded 在 webhook 之后。
    • 啊,是的,这是有道理的,欢迎来到 Stripe 社区! :D 尝试使用 PaymentIntent ID 的棘手之处在于,当您重定向时不知道它。直到用户成功完成结帐后才会创建 PaymentIntent ID。在他们成功完成结帐后,是的,最好将 PaymentIntent 的 ID 与您的用户一起存储以便以后记帐。
    猜你喜欢
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多