繁体   English   中英

如何延迟来自用户表单的 POST 请求,直到收到来自 Stripe 的 webhook POST 之后?

[英]How can I delay a POST request from a user form until AFTER a webhook POST from Stripe is received?

我希望用户在处理来自前端表单的 POST 请求之前支付费用。 我有一个在后端可以正常工作的 Stripe webhook,但我不确定如何将表单的前端发布延迟到收到付款确认之后。

在下面的代码中,现在createTourcreateTourPay同时运行。 我希望createTourPay首先执行,并且createTour仅在 Stripe 从 webhook 发布到我的应用程序后触发。 我怎样才能做到这一点?

Controller 文件(webhook):

exports.webhookCheckout = (req, res, next) => {
  const signature = req.headers['stripe-signature'];
  let event;
  try {
    event = stripe.webhooks.constructEvent(
      req.body,
      signature,
      process.env.STRIPE_WEBHOOK_SECRET
    );
  } catch (err) {
    return res.status(400).send(`Webhook error: ${err.message}`);
  }
  if (
    event.type === 'checkout.session.completed' &&
    event.line_items.name === 'New Job Purchase'
  ) {
    res.status(200).json({ recieved: true });
    // Somehow, I want this to trigger the execution of the POST request in my front end JS file.
  } else {
    if (event.type === 'checkout.session.completed')
      createBookingCheckout(event.data.object);
    res.status(200).json({ recieved: true });
  }
};

前端JS文件:

export const createTourPay = async myForm => {
  try {
    // 1) Get the checkout session from API response
    const session = await axios(`/api/v1/tours/tour-pay`);
    const complete = 1;
    // console.log(session);
    // 2) Create checkout form + charge the credit card
    await stripe.redirectToCheckout({
      sessionId: session.data.session.id
    });
  } catch (err) {
    // console.log(err);
    showAlert('error', err);
  }
};

export const createTour = async myForm => {
  try {
    const startLocation = {
      type: 'Point',
      coordinates: [-10.185942, 95.774772],
      address: '123 Main Street',
      description: 'Candy Land'
    };

    const res = await axios({
      method: 'POST',
      headers: {
        'Content-Type': `multipart/form-data; boundary=${myForm._boundary}`
      },
      url: '/api/v1/tours',
      data: myForm
    });

    if (res.data.status === 'success') {
      showAlert('success', 'NEW TOUR CREATED!');
      window.setTimeout(() => {
        location.assign('/');
      }, 1500);
    }
  } catch (err) {
    showAlert('error', err.response.data.message);
  }
};

广泛地说:不要这样做。 相反,您实际上应该在系统中创建一些待定/未付费版本的“旅游”(或任何其他产品/服务),然后在创建时将唯一 ID(例如: tour_123 )附加到结帐 session ,或者使用client_reference_id ( doc ) 或metadata ( doc ):

const session = await stripe.checkout.sessions.create({
  // ... other params
  client_reference_id: 'tour_123',
  metadata: { tour_id: 'tour_123' },
});

然后,您将使用 webhook 来检查这些值,并更新您自己的数据库以指示已付款并且您可以向客户履行订单(运送产品、发送代码、允许访问服务等)。

如果您真的想继续使用更同步的流程,您可以使用单独的身份验证和捕获来对您的客户体验进行排序,并在授权和创建您的旅游实体后捕获资金

编辑:关于安全的说明

您永远不应该相信客户端逻辑来进行受限操作,例如创建“付费”旅游。 例如,有动力的用户可以简单地调用您的/api/v1/tours创建端点,而无需通过您的支付流程。 除非您验证付款并在您的服务器上跟踪 state,否则您将无法知道其中哪些实际支付了您。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM