获取 SvelteKit 端点请求的原始正文

Max*_*man 10 node.js stripe-payments sveltekit

我的 SvelteKit 应用程序中有一个端点,用于处理来自 Stripe 的 Webhook 请求。每个请求都经过签名,以便可以验证它是否来自 Stripe。

我必须验证该事件是否来自 Stripe 的代码如下所示:

import Stripe from "stripe";

const WEBHOOK_SECRET = process.env["STRIPE_WH_SECRET"];

const stripe = new Stripe(process.env["STRIPE_SECRET"], {
  apiVersion: "2020-08-27",
});

export async function post({ headers, body }) {
  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(
      body,
      headers["stripe-signature"],
      WEBHOOK_SECRET
    );
  } catch (err) {
    return {
      status: 400,
      body: err,
    };
  }

  // Do stuff with the event
}
Run Code Online (Sandbox Code Playgroud)

但是当它收到来自 Stripe 的事件时,我收到此错误:

No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing
Run Code Online (Sandbox Code Playgroud)

经过一番研究,我发现这个函数在调用SvelteKit hooks之前就将 body 解析为 JSON ,这意味着无法直接获取原始 body,所以我决定最好的选择是尝试重建原始 body:

event = stripe.webhooks.constructEvent(
  JSON.stringify(body),
  headers["stripe-signature"],
  WH_SECRET
);
Run Code Online (Sandbox Code Playgroud)

我不完全确定为什么这不起作用,因为在深入研究Stripe 库中的相关代码后,它似乎可以很好地处理字符串。我最好的猜测是,在某些时候编码会变得混乱。

对此的任何帮助将不胜感激,因为我真的很想避免放弃 SvelteKit,因为我实际上已经用它完成了我的项目(回想起来,这不是一个好主意)。

Nik*_*kov 11

这是在 Svelte Kit 中获取请求的原始正文的方法:

// routeName/+server.js
export async function POST({ request }) {
    const rawBody = await request.text()
    ...
}
Run Code Online (Sandbox Code Playgroud)

我在处理 Stripe 和 Svelte Kit 时也发现了这一点。


小智 3

接受的有效负载stripe.webhooks.constructEvent(payload, signature, secret)必须是 type string | Buffer,但 SvelteKit 请求中收到的 rawBody 是 type Uint8Array

将 Uint8Array rawBody 或 JSON.stringify'd rawBody 作为有效负载传递会导致 Stripe 出现以下错误。参考: https: //github.com/stripe/stripe-node#webhook-signing

错误 message: 'No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing'

我们需要将 rawBody 转换为stringBuffer而不改变内容。为了实现这一点,我们可以使用:Buffer.from(rawBody)

所以你的端点看起来像:

...
const stripeWebhookSecret = process.env['STRIPE_WEBHOOK_SECRET'];

export const post: RequestHandler = async (request) => {
  const rawBody = Buffer.from(request.rawBody);
  const signature = request.headers['stripe-signature'];

  try {
    event = stripe.webhooks.constructEvent(
      rawBody,
      signature,
      stripeWebhookSecret
    );
...
Run Code Online (Sandbox Code Playgroud)

  • 知道如何在 https://github.com/sveltejs/kit/pull/3384 之后执行此操作,因为“rawBody”不再暴露? (5认同)