【问题标题】:Getting the raw body of a request to a SvelteKit endpoint将请求的原始正文获取到 SvelteKit 端点
【发布时间】:2022-04-04 09:21:45
【问题描述】:

我的 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
}

但是当它从 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

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

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

我不完全确定为什么这不起作用,因为在the relevant code in the Stripe library 中挖掘之后,它似乎可以很好地处理字符串。我最好的猜测是,在某些时候编码会变得混乱。

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

【问题讨论】:

  • 我对 SvelteKit 不够熟悉,无法评论获取原始正文,但您绝对需要 Stripe 请求中的原始(未重建)原始正文来验证有效负载。可能值得通过官方文档中的链接直接向SvelteKit team 询问(如何避免解析请求)。
  • @taintedzodiac 我确实联系过那里但没有得到任何答案。此外,除非我遗漏了一些非常奇怪的东西,否则如果不编写自定义适配器就无法获得原始主体,即使那样它也无法在开发服务器中工作。感谢您确认我需要得到真正的原始身体。

标签: node.js stripe-payments sveltekit


【解决方案1】:

stripe.webhooks.constructEvent(payload, signature, secret) 接受的负载必须是 string | Buffer 类型,但在 SvelteKit 请求中收到的 rawBody 类型是 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
    );
...

【讨论】:

【解决方案2】:

请求现在带有一个 arrayBuffer,可以像这样转换为原始正文:

function toBuffer(ab: any) {
  const buf = Buffer.alloc(ab.byteLength);
  const view = new Uint8Array(ab);
  for (let i = 0; i < buf.length; ++i) {
    buf[i] = view[i];
  }
  return buf;
}

export async function post(event: RequestEvent<Record<string, string>>) {
   ...
  const preRawBody = await event.request.arrayBuffer();
  const rawBody = toBuffer(preRawBody);
  
  try {
    stripeEvent = stripe.webhooks.constructEvent(
      rawBody,
      stripeSignature,
      process.env.STRIPE_WEBHOOK_SECRET
    );
  } ...
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-07
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2016-02-11
    相关资源
    最近更新 更多