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

Next.js 14集成PayHere支付网关,支付状态无法写入数据库

Next.js 14集成PayHere支付网关:支付成功后无法更新数据库状态的排查与修复

问题背景

开发Next.js 14项目时集成PayHere支付网关,按照官方文档通过notify_url接收支付状态通知,将官方提供的PHP验证逻辑转为TypeScript并实现webhook接口,但支付完成后数据库中的订单状态无法更新。

核心问题排查与修复方案

1. Prisma异步操作未等待(最常见原因)

原webhook代码中,prisma.order.update调用未添加await,导致数据库更新操作在未完成时就返回了响应,异步任务被丢弃,数据库不会执行更新。

修复:
在Prisma操作前添加await,并捕获可能的错误:

// 原代码
prisma.order.update({
  where: { id: order_id },
  data: { status: "complete" },
});

// 修复后
try {
  await prisma.order.update({
    where: { id: order_id },
    data: { status: "complete" },
  });
  console.log("订单状态更新成功");
} catch (dbError) {
  console.error("数据库更新失败:", dbError);
}

2. MD5签名验证的大小写不匹配

PayHere官方验证逻辑要求对merchant_secret的MD5结果先转大写,再参与最终签名计算。原TS代码中仅对最终MD5结果转大写,但内部的merchant_secret MD5结果是小写,导致签名验证失败,无法进入更新逻辑。

修复:
对merchant_secret的MD5结果也执行toUpperCase():

// 原代码
crypto.createHash("md5").update(merchant_secret).digest("hex")

// 修复后
crypto.createHash("md5").update(merchant_secret).digest("hex").toUpperCase()

完整的签名计算代码:

const local_md5sig = crypto
  .createHash("md5")
  .update(
    merchant_id +
      order_id +
      payhere_amount +
      payhere_currency +
      status_code +
      crypto.createHash("md5").update(merchant_secret).digest("hex").toUpperCase()
  )
  .digest("hex")
  .toUpperCase();

3. PayHere通知的请求解析问题

PayHere默认通过x-www-form-urlencoded格式发送通知,而非JSON。如果是Next.js App Router的API路由,默认配置可能无法正确解析该格式,导致req.body参数缺失。

修复(App Router场景):
禁用默认JSON解析,使用第三方库手动解析表单数据:

import formidable from 'formidable';

export const config = {
  api: { bodyParser: false },
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    const form = formidable({});
    const [fields, files] = await form.parse(req);
    // 从fields中获取参数(PayHere的参数是数组格式,需取第一个元素)
    const merchant_id = fields.merchant_id?.[0];
    const order_id = fields.order_id?.[0];
    const payhere_amount = fields.payhere_amount?.[0];
    // 后续验证与更新逻辑...
  }
}

4. Order ID类型不匹配

如果数据库中order表的id是数字类型,而PayHere通知中的order_id是字符串,会导致Prisma的where条件匹配失败,无法找到对应订单。

修复:
根据数据库中id的类型转换order_id:

// 若id为数字类型
where: { id: Number(order_id) }
// 若id为UUID或字符串类型,直接使用
where: { id: order_id }

调试建议

  • 在webhook中添加详细日志,打印req.body的所有参数,确认是否正确接收PayHere的通知数据;
  • 打印local_md5sig和md5sig的值,对比是否一致,排查签名验证问题;
  • 捕获Prisma操作的错误,打印错误信息,确认是否存在数据库连接或权限问题;
  • 使用PayHere的测试工具模拟通知请求,验证webhook的响应是否符合要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:18:10