You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Sails框架中访问Stripe API原始数据及解决Webhook签名验证失败问题

在Sails框架中使用Stripe的常见问题解决

我来帮你解决这两个在Sails中对接Stripe时遇到的问题:

1. 如何访问Stripe API的原始数据?

当你通过Stripe Node SDK调用API时,返回的结果默认是经过封装的对象。如果需要获取Stripe API返回的原始响应数据,可以直接访问返回对象的raw属性——不管是成功响应还是错误信息,都能拿到原始的JSON数据。

举个实际的例子,创建支付Intent时获取原始数据:

const stripe = require('stripe')(sails.config.stripe.secretKey);

try {
  const paymentIntent = await stripe.paymentIntents.create({
    amount: 1000,
    currency: 'usd',
  });
  // 获取API返回的原始响应
  const rawApiResponse = paymentIntent.raw;
  console.log('Stripe原始响应:', rawApiResponse);
} catch (err) {
  // 错误场景下,原始错误数据也在err.raw里
  console.error('Stripe错误原始数据:', err.raw);
}

2. 解决Stripe Webhook签名验证失败与请求体丢失问题

你遇到的核心问题是:Stripe签名验证需要未被修改的原始请求体,但Sails默认的bodyParser会解析请求体并修改它,直接绕过又会导致req.body丢失。下面是一套完整的解决方案:

步骤1:自定义中间件捕获原始请求体

在config/http.js中添加一个自定义中间件,专门为Stripe Webhook路由捕获原始请求体,同时手动解析出req.body供后续业务使用:

module.exports.http = {
  middleware: {
    // 自定义中间件:捕获Stripe Webhook的原始请求体
    stripeWebhookRawBody: function(req, res, next) {
      // 只针对你的Stripe Webhook路由(比如 /webhooks/stripe)
      if (req.path === '/webhooks/stripe' && req.method === 'POST') {
        let rawBody = '';
        // 监听请求数据事件,拼接原始内容
        req.on('data', chunk => {
          rawBody += chunk.toString();
        });
        // 请求结束后挂载原始数据,并手动解析JSON
        req.on('end', () => {
          req.rawBody = rawBody;
          try {
            req.body = JSON.parse(rawBody);
          } catch (err) {
            return res.sendStatus(400);
          }
          next();
        });
      } else {
        // 非Webhook路由直接跳过
        next();
      }
    },

    // 调整中间件顺序,把自定义的放在bodyParser前面
    order: [
      'stripeWebhookRawBody',
      'cookieParser',
      'session',
      'bodyParser',
      // ...保留你原来的其他中间件
    ],

    // 为Webhook路由绕过默认的bodyParser
    bodyParser: (function configureBodyParser(){
      const skipper = require('skipper');
      const defaultBodyParser = skipper();
      return function(req, res, next) {
        // 跳过Stripe Webhook路由的自动解析
        if (req.path === '/webhooks/stripe' && req.method === 'POST') {
          return next();
        }
        return defaultBodyParser(req, res, next);
      };
    })(),
  }
};

步骤2:在控制器中验证签名并处理事件

现在你的Webhook控制器可以同时拿到req.rawBody(用于签名验证)和req.body(用于业务处理)了:

// api/controllers/WebhookController.js
module.exports = {
  stripe: async function(req, res) {
    const stripe = require('stripe')(sails.config.stripe.secretKey);
    const webhookSecret = sails.config.stripe.webhookSecret;
    const signature = req.headers['stripe-signature'];

    let stripeEvent;
    try {
      // 使用原始请求体验证签名
      stripeEvent = stripe.webhooks.constructEvent(
        req.rawBody,
        signature,
        webhookSecret
      );
    } catch (err) {
      console.error('Stripe签名验证失败:', err.message);
      return res.status(400).send(`Webhook Error: ${err.message}`);
    }

    // 根据事件类型处理业务逻辑
    switch (stripeEvent.type) {
      case 'payment_intent.succeeded':
        const paymentIntent = stripeEvent.data.object;
        console.log('支付成功:', paymentIntent.id);
        // 这里添加你的业务逻辑,比如更新订单状态
        break;
      case 'charge.failed':
        const failedCharge = stripeEvent.data.object;
        console.log('支付失败:', failedCharge.id);
        // 处理支付失败的逻辑
        break;
      // 其他你需要处理的事件类型...
      default:
        console.log(`未处理的事件类型: ${stripeEvent.type}`);
    }

    // 返回200给Stripe,确认收到事件
    res.sendStatus(200);
  }
};

关于"重复造轮子"的疑问

目前Sails生态里确实没有官方维护的Stripe Webhook集成组件,大部分开发者都是基于Stripe官方Node SDK自己适配Sails的中间件体系——所以你的实现不算重复造轮子,只是在Sails的框架规则下对接Stripe的标准功能而已。毕竟Stripe的Webhook验证逻辑是固定的,我们只需要在Sails里做好原始请求体的捕获就行。

内容的提问来源于stack exchange,提问作者matt9292

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 04:17:39