PAYATHON 2026

使用serverless调用支付宝支付时如何生成outerOrderNo?

支付老李

结论

outerOrderNo 是商户侧订单号,应由业务系统自行生成。通常既没有必要,也不应通过支付宝 API 提前获取。

支付宝受理支付请求后,会生成平台交易号,例如 trade_no。outerOrderNo 则用于标识商户自己的订单,二者不能混用。

为什么需要自行生成

商户订单号要在发起支付前生成,用于关联业务订单、支付请求和支付结果。支付宝也会通过该字段识别交易,因此它还用于幂等控制和问题排查。

outerOrderNo 通常需要满足以下要求:

  • 在商户系统内保持唯一。
  • 创建订单时生成,不要在每次调用支付接口时重新生成。
  • 同一订单重试支付时,订单号保持不变。
  • 只使用支付接口允许的字符,并遵守字段长度限制。
  • 不要直接使用手机号、身份证号等敏感信息。

不同 Serverless 支付能力、SDK 或接口版本对字段长度和字符的限制可能不同,请以对应的接口文档为准。

推荐处理流程

  1. 用户提交购买请求。
  2. 业务服务创建本地订单。
  3. 服务端生成唯一的 outerOrderNo。
  4. 保存订单号和订单状态。
  5. 调用支付宝支付能力,并传入该订单号。
  6. 支付完成后,根据回调或主动查询结果更新本地订单。

订单号不要在客户端生成。客户端提交的编号可能被篡改,也可能因重复点击发生冲突。

Node.js 示例

以下代码使用“时间戳 + 随机值”生成订单号:

import crypto from 'node:crypto';

function generateOuterOrderNo() {
  const timestamp = Date.now().toString();
  const randomPart = crypto.randomBytes(8).toString('hex');

  return `PAY${timestamp}${randomPart}`;
}

const outerOrderNo = generateOuterOrderNo();

console.log(outerOrderNo);

订单号应在创建订单时生成并保存:

async function createOrder(orderRepository, userId, amount) {
  const outerOrderNo = generateOuterOrderNo();

  const order = {
    outerOrderNo,
    userId,
    amount,
    status: 'PENDING'
  };

  await orderRepository.insert(order);

  return order;
}

调用支付能力时,直接使用数据库中保存的订单号:

const order = await orderRepository.findById(orderId);

const paymentParams = {
  outerOrderNo: order.outerOrderNo,
  totalAmount: order.amount,
  subject: '商品订单'
};

// 将 paymentParams 传给实际使用的支付宝 Serverless 支付接口

示例中的 totalAmount 和 subject 只用于说明参数之间的关系。实际参数名称请以当前使用的支付宝 Serverless API 定义为准。

高并发场景的生成方式

只使用时间戳,无法保证订单号在并发环境中绝对唯一。生产系统可以采用以下方式:

  • 使用 UUID,并根据接口限制去掉连字符。
  • 组合数据库自增 ID 和业务前缀。
  • 使用 Snowflake ID 等分布式 ID。
  • 组合时间戳、实例标识和随机数。

无论采用哪种方式,都建议为数据库中的 outerOrderNo 字段建立唯一索引,在存储层约束唯一性。

注意事项

支付重试不要更换订单号

首次调用超时并不等于支付失败,此时不要立即生成新的 outerOrderNo。应先查询原订单状态,再决定重试还是关闭订单,否则可能导致重复支付,或让同一个业务订单对应多笔交易。

不要使用纯随机短字符串

随着订单量增加,短随机字符串更容易发生碰撞。即使理论上的碰撞概率不高,也应配合数据库唯一索引使用,并在冲突时重新生成。

区分商户订单号和支付宝交易号

  • outerOrderNo:由商户系统生成,在发起支付前已经存在。
  • trade_no:由支付宝受理交易后生成,通常可以从支付响应、异步通知或查询结果中获得。

正确的流程是先在自己的 Serverless 服务中创建业务订单并生成 outerOrderNo,再调用支付宝支付接口,而不是调用支付宝 API 预先申请商户订单号。

备注:内容仅供参考。