尽管配置正确,Express.js Stripe Webhook 路由仍返回 404 错误

问题描述 投票:0回答:1

总结

我正在开发一个 Express.js 应用程序来处理 Stripe webhooks。尽管按照建议配置了 Webhook 路由,但当 Stripe 尝试将事件发布到我的 Webhook 端点时,我仍然遇到

404 Not Found
错误。

环境

  • Node.js 版本:[v20.14.0]
  • Express 版本:[4.18.2]
  • 条纹版本:[1.19.5]

问题描述

当我运行 Stripe CLI 将事件转发到本地服务器时,每个事件都会收到

404 Not Found
错误。以下是错误消息的详细信息:

2024-06-09 16:30:24   --> invoice.paid [evt_1PPfGkRsJfE0QDMT8OOiGWVh]
2024-06-09 16:30:24  <--  [404] POST http://localhost:3080/webhook [evt_1PPfGkRsJfE0QDMT8OOiGWVh]

服务器代码(index.js)


javascript
require('dotenv').config();
const path = require('path');
const express = require('express');
const cors = require('cors');
const mongoSanitize = require('express-mongo-sanitize');
const routes = require('./routes');
const webhookRoutes = require('./routes/webhookRoutes');

const { PORT, HOST } = process.env;
const port = Number(PORT) || 3080;
const host = HOST || 'localhost';

const app = express();
app.disable('x-powered-by');

app.use(cors());
app.use(express.json({ limit: '3mb' }));
app.use(mongoSanitize());
app.use(express.urlencoded({ extended: true, limit: '3mb' }));

// Webhook route must handle raw request bodies for signature verification
app.use('/webhook', express.raw({ type: 'application/json' }), webhookRoutes);

app.use('/api', routes); // Example for other routes

app.use((req, res) => {
  res.status(404).sendFile(path.join(__dirname, 'public', '404.html'));
});

app.listen(port, host, () => {
  console.log(`Server listening at http://${host}:${port}`);
});

Webhook 路由 (webhookRoutes.js)

javascript
Copy code
const express = require('express');
const router = express.Router();
const { handleWebhook } = require('../controllers/webhookController');

router.post('/', express.raw({ type: 'application/json' }), handleWebhook);

module.exports = router;

Webhook 控制器 (webhookController.js)

javascript
Copy code
const Stripe = require('stripe');
const { updateUserSubscriptionStatus } = require('../../models/userMethods');
const { logger } = require('~/config');

const stripe = Stripe(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_ENDPOINT_SECRET;

const handleWebhook = async (req, res) => {
  logger.info('Received a webhook event');
  let event = req.body;

  // Verify webhook signature
  if (endpointSecret) {
    const signature = req.headers['stripe-signature'];
    try {
      event = stripe.webhooks.constructEvent(req.body, signature, endpointSecret);
      logger.info('Webhook signature verified');
    } catch (err) {
      logger.error('⚠️  Webhook signature verification failed:', err.message);
      return res.status(400).send(`Webhook Error: ${err.message}`);
    }
  }

  try {
    switch (event.type) {
      case 'invoice.paid': {
        const invoice = event.data.object;
        const customerId = invoice.customer;
        logger.info(`Handling invoice.paid for customer ${customerId}`);

        const updateResult = await updateUserSubscriptionStatus(customerId, 'active');
        if (updateResult instanceof Error) {
          logger.error('[updateUserSubscriptionStatus]', updateResult);
          const { status, message } = updateResult;
          return res.status(status).send({ message });
        }

        logger.info('User subscription status updated successfully');
        res.status(200).send('Success');
        break;
      }
      case 'payment_intent.succeeded': {
        const paymentIntent = event.data.object;
        logger.info(`PaymentIntent for ${paymentIntent.amount} was successful!`);
        res.status(200).send('Success');
        break;
      }
      case 'payment_method.attached': {
        const paymentMethod = event.data.object;
        logger.info('PaymentMethod successfully attached');
        res.status(200).send('Success');
        break;
      }
      default: {
        logger.warn(`Unhandled event type ${event.type}`);
        res.status(400).send(`Unhandled event type ${event.type}`);
      }
    }
  } catch (err) {
    logger.error('[handleWebhook]', err);
    res.status(500).json({ message: err.message });
  }
};

module.exports = {
  handleWebhook,
};

重现步骤 启动服务器:

节点索引.js 使用 Stripe CLI 转发事件:

启动 Stripe CLI 监听事件并将其转发到本地服务器:

stripe 监听 --forward-to http://localhost:3080/webhook 触发测试事件:

使用 Stripe CLI 触发测试事件:

条纹触发发票.已付款 预期行为 Webhook 端点应正确接收和处理 Stripe 事件,服务器应记录事件并以 200 状态代码进行响应。

实际行为 服务器响应 Webhook 端点的 404 Not Found 错误。

请求帮助 如果您能帮助我诊断 webhook 端点未被识别的原因以及如何修复 404 错误,我将不胜感激。谢谢!

node.js stripe-payments webhooks
1个回答
0
投票

您应该在 webhook 路由之后使用主体解析器中间件

© www.soinside.com 2019 - 2024. All rights reserved.