因此,我正在为多个用例设置 stripe webhooks,并且按照文档,我无法获得有效的 webhook 响应。我一直收到此错误。
“Webhook 错误:未找到与有效负载的预期签名匹配的签名。您是否正在传递从 Stripe 收到的原始请求正文?”
我遵循了文档并理解这只是意味着我需要将正文转换为原始数据而不是其他格式(条纹需要原始数据才能建立安全连接)。我尝试用几种不同的方式来做到这一点(我在下面有一些)。
app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
新代码尝试:
app.use((req, res, next) => {
if (req.originalUrl === "/webhook") {
next();
} else {
bodyParser.json()(req, res, next);
}
});
app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => {
如您所见,我尝试了 stripe 文档推荐的所有方法,甚至尝试了 thisimilar SOF Question 中的一些方法,但无法做到。我还尝试过使用 bodyPaser 或express,并尝试了一些较小的事情。在我们的应用程序中,我们使用的是 firebase 后端,具有几个正常的云功能,并且我们决定对所有条带代码使用express,因为这是条带文档使用的。在尝试了express和fierbase这么长时间之后,我决定只使用firebase onRequest方法并使用req.rawBody方法。
exports.stripeWebhook = functions.https.onRequest((request, response) => {
const stripeWebhookSecretKey = functions.config().stripe.webhook_secret_key;
let event;
...
const payloadData = request.rawBody;
const payloadString = payloadData.toString();
const webhookStripeSignatureHeader = request.headers['stripe-signature'];
event = stripe.webhooks.constructEvent(payloadString, webhookStripeSignatureHeader, stripeWebhookSecretKey);
...
});
这很快就起作用了,尽管我认为我的老板不会介意,但将所有条带代码都放在 Express 中是理想的选择,只是想知道为什么会发生这种情况。谢谢
Stripe 需要请求的原始正文来执行签名验证。如果您使用框架,请确保它不会操纵原始主体。对请求原始正文的任何操作都会导致验证失败。[1]
出现“未找到与有效负载的预期签名匹配的签名”错误的两个主要原因是:
您可以参考这个完整的 Firebase 函数示例,它为 Stripe Events[3] 实现了 Webhook 端点。
Firebase SDK 似乎确实在调用 Express 应用程序之前转换请求。用于获取原始请求正文的已记录代码示例都不起作用,因为在调用 Express 之前,正文已被解析为 JSON 对象。
Firebase SDK 保留原始有线格式,并在
rawBody
上使用扩展 functions.https.Request
的 express.Request
属性。
/** An express request with the wire format representation of the request body. */
export interface Request extends express.Request {
/** The wire format representation of the request body. */
rawBody: Buffer;
}
请参阅 Firebase Functions Github 存储库中的 https.ts
生成的
rawBody
应该可用于 express.Request
对象上的 Express 应用程序。您需要将 rawBody: Buffer
转换为 Stripe SDK 的字符串,并且可能需要类型断言才能在 Typescript 中访问 rawBody
。
app.post("/webhook", (
request: express.Request,
response: express.Response,
) => {
const rawBody = (request as unknown as functions.https.Request).rawBody;
const rawBodyString = rawBody.toString("utf8");
...
});