我正在在 Firebase Cloud Functions 上运行的 Node/Express.ts 后端实现 Stripe webhook 集成,并且在签名验证期间很难传递 raw req.body。
我已经进行了十几次尝试和修复,我不断遇到的错误是:“Webhook 错误:Webhook 负载必须以字符串或缓冲区形式提供(https://nodejs.org/api/buffer.html )表示原始请求正文的实例是作为解析的 JavaScript 对象提供的,如果不访问原始签名的材料,则无法进行签名验证。“
这是我的index.ts:
const app = express();
app.use(cors());
app.use(allowedOriginsHandler);
app.post("/api/v1/stripe/webhook/payment", express.raw({ type: '*/*' }), listenToPaymentEvents);
app.use(express.json());
app.use("/api/v1", routes);
app.use(errorLogger);
app.use(errorResponder);
app.use(failSafeHandler);
export const httpFunction = functions.https.onRequest(app);
//admin.initializeApp();
//MARKETPLACE CLOUD FUNCTIONS
//orders
export const onOrderDocumentCreateFunction = onOrderDocumentCreate;
export const onOrderStatusChangeFunction = onOrderStatusChange;
//check order products availability
export const onOrderByVendorCreateFunction = onCreateOrderByVendor;
//products (create/update subcollections)
export const onProductDocumentCreateFunction = onCreateProduct;
export const onProductDocumentUpdateFunction = onUpdateProduct;
//Update seller public info collection on seller create/update
export const onSellerCreateFunction = onCreateSeller;
export const onSellerUpdateFunction = onUpdateSeller;
export const onUserRegistrationFunction = onUserRegistration;
// Create seller products bulk upload template on seller create
// and update seller document with the template url info
export const createSellerBulkUploadTemplateFunction =
createSellerBulkUploadTemplate;
以下是其他路由的配置:
const router = Router();
router.route("/newsletter").post(addContactToNewsletter);
router.route("/checkout").post(
firebaseAuthenticationHandler,
checkProductsAvailabilityHandler,
checkProductsPriceChangesHandler,
lockProductsHandler,
checkout
);
router.route("/order/vendor/cancel/:id").put(
firebaseAuthenticationHandler,
orderCancelledByVendor
);
router.route("/order/buyer/cancel").post(orderCancelledByBuyer);
router.route("/order/vendor/processing/:id").put(
firebaseAuthenticationHandler,
updateOrderToProcessing
);
export default router;
这是处理 webhook 的控制器:
dotenv.config();
const stripePaymentIntentWebhookEndpointSecret =
process.env.STRIPE_PAYMENT_INTENT_WEBHOOK_ENDPOINT_SECRET ?? "";
export const listenToPaymentEvents: RequestHandler = async (req, res) => {
const sig = req.headers["stripe-signature"];
if (!sig) {
console.log("Missing Stripe signature");
res.status(400).send("Missing Stripe signature");
return;
}
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
sig,
stripePaymentIntentWebhookEndpointSecret
);
switch (event.type) {
case "payment_intent.payment_failed": {
const paymentIntentPaymentFailed = event.data.object;
console.log(paymentIntentPaymentFailed);
break;
}
case "payment_intent.succeeded": {
const paymentIntentSucceeded = event.data.object;
await handlePaymentIntentSuccess(paymentIntentSucceeded);
break;
}
default: {
console.log(`Unhandled event type ${event.type}`);
}
}
res.status(200).send("Event received");
} catch (error) {
if (error instanceof Error) {
res.status(500).send(`Webhook Error: ${error.message}`);
} else {
res.status(500).send("Webhook Error: An unexpected error occurred");
}
}
};
我做错了什么?
我的猜测是
app.use(express.json());
中间件,因为错误消息提到内容是 JSON 而不是原始字符串。我会删除该行,看看您是否收到相同的错误消息。