PAYATHON 2026

小红书小程序如何跳转并唤起支付宝完成订单支付?

支付老李

结论

前端流程可以分为五个阶段:订单确认页 → 收银台页 → 服务端创建支付宝支付 → 唤起支付宝 → 返回后查询订单状态。

需要注意,小红书小程序是否能直接唤起支付宝、具体使用哪个 API,取决于开放平台当前提供的能力、客户端版本和应用资质。不要自行拼接 alipays:// Scheme,也不要在前端存放支付宝私钥或执行签名。如果平台不支持直接唤起,通常需要跳转到已加入白名单的 H5 收银台,再使用服务端返回的支付宝支付地址。

推荐流程

1. 创建订单

用户点击“立即支付”后,前端先请求业务服务端创建订单。服务端返回业务订单号,此时订单仍不能视为已支付。

async function createOrder() {
  const result = await request({
    url: '/api/orders',
    method: 'POST',
    data: {
      skuId: currentSkuId,
      quantity: 1,
      addressId: selectedAddressId
    }
  });

  return result.orderNo;
}

服务端需要重新计算商品价格、优惠和运费,不能直接采用前端提交的金额。

2. 跳转到收银台页面

订单创建成功后,前端跳转到小程序内的收银台页,并通过订单号加载支付信息。

下面用常见的 xhs.navigateTo 写法演示,实际 API 名称和参数应以接入的小红书小程序 SDK 文档为准。

async function submitOrder() {
  try {
    const orderNo = await createOrder();

    xhs.navigateTo({
      url: `/pages/cashier/index?orderNo=${encodeURIComponent(orderNo)}`
    });
  } catch (error) {
    showToast('订单创建失败,请稍后重试');
  }
}

不要通过页面参数直接传递金额、支付宝交易号或完整支付地址。收银台页应使用 orderNo 向服务端重新查询。

唤起支付宝

收银台页加载后,需要调用服务端支付接口。服务端负责:

  1. 校验订单状态和支付金额。
  2. 调用支付宝服务端接口创建支付。
  3. 保存业务订单号与支付宝交易信息的对应关系。
  4. 对请求参数进行签名。
  5. 返回平台允许使用的唤起参数或 H5 支付地址。
async function createAlipay(orderNo) {
  return request({
    url: `/api/orders/${encodeURIComponent(orderNo)}/payments`,
    method: 'POST',
    data: {
      channel: 'ALIPAY'
    }
  });
}

方案一:使用小红书开放平台提供的支付或外部应用能力

如果开放平台明确提供了支付宝唤起 API,应把服务端返回的参数原样传给该 API:

async function payWithPlatformApi(orderNo) {
  const payment = await createAlipay(orderNo);

  // platformPaymentApi 仅为占位名称,
  // 必须替换为小红书开放平台实际提供的 API。
  platformPaymentApi({
    paymentData: payment.paymentData,

    success() {
      confirmPaymentResult(orderNo);
    },

    fail(error) {
      handlePaymentInterrupt(orderNo, error);
    }
  });
}

这里没有指定具体的唤起 API,因为不同接入模式、应用资质和 SDK 版本可能支持不同能力。接入前应确认开放平台是否允许小程序跳转支付宝,以及需要配置哪些域名、Scheme 和支付权限。

方案二:跳转到 H5 收银台

如果接入方案要求先进入指定页面,可以由服务端返回经过校验的 H5 收银台地址,再让小程序打开已配置业务域名的 WebView 页面。

小程序端示例:

async function openH5Cashier(orderNo) {
  const payment = await createAlipay(orderNo);

  if (!payment.cashierUrl) {
    throw new Error('服务端未返回收银台地址');
  }

  xhs.navigateTo({
    url:
      '/pages/webview/index?url=' +
      encodeURIComponent(payment.cashierUrl)
  });
}

WebView 页面接收并加载该地址:

<web-view src="{{url}}"></web-view>

H5 收银台使用服务端返回的支付宝支付地址发起跳转:

async function startAlipay(orderNo) {
  const response = await fetch(`/api/h5/orders/${encodeURIComponent(orderNo)}/alipay`, {
    method: 'POST',
    credentials: 'include'
  });

  if (!response.ok) {
    throw new Error('创建支付失败');
  }

  const result = await response.json();

  // payUrl 必须由可信服务端生成并校验。
  window.location.assign(result.payUrl);
}

该地址能否在小红书内置 WebView 中唤起支付宝,需要通过真机测试确认,同时还要符合小红书和支付宝双方的域名、跳转和安全策略。如果客户端拦截外部跳转,应改用开放平台认可的支付能力,不能通过未经允许的 URL Scheme 绕过限制。

支付结果处理

前端回调不能作为最终依据

成功唤起支付宝只说明支付宝页面已经打开,不代表用户付款成功。支付 API 返回成功,也可能仅表示调用成功。实际使用中还可能出现以下情况:

  • 用户付款后没有返回小红书。
  • 用户在支付过程中取消。
  • 网络中断,前端没有收到结果。
  • 前端显示失败,但支付宝异步通知稍后到达。
  • 用户反复点击,导致重复创建支付请求。

因此,订单是否支付成功必须由服务端确认。

服务端接收支付宝异步通知

服务端收到支付宝通知后,需要:

  1. 验证支付宝签名。
  2. 校验商户号、应用 ID、业务订单号和金额。
  3. 判断交易状态。
  4. 以幂等方式把订单更新为已支付。
  5. 按支付宝协议返回通知响应。

前端不能参与验签,也不能保存支付宝应用私钥。

返回小程序后主动查询

收银台页重新显示时,应主动查询订单状态。从支付宝返回后,页面通常不会重新创建,如果只在 onLoad 中查询,很容易漏掉支付结果。

Page({
  data: {
    orderNo: '',
    checking: false
  },

  onLoad(options) {
    this.setData({
      orderNo: decodeURIComponent(options.orderNo || '')
    });
  },

  onShow() {
    if (this.data.orderNo) {
      this.queryPaymentResult();
    }
  },

  async queryPaymentResult() {
    if (this.data.checking) {
      return;
    }

    this.setData({ checking: true });

    try {
      const order = await request({
        url: `/api/orders/${encodeURIComponent(this.data.orderNo)}`,
        method: 'GET'
      });

      if (order.status === 'PAID') {
        xhs.redirectTo({
          url:
            '/pages/pay-result/index?status=success&orderNo=' +
            encodeURIComponent(this.data.orderNo)
        });
      } else if (order.status === 'CLOSED') {
        showToast('订单已关闭');
      } else {
        this.setData({
          paymentStatus: 'PENDING'
        });
      }
    } catch (error) {
      showToast('支付结果查询失败,请稍后刷新');
    } finally {
      this.setData({ checking: false });
    }
  }
});

xhs.redirectTo 也是示意写法,使用前应根据实际 SDK 核对。重定向可以避免用户返回后再次进入支付页。

如果支付宝异步通知存在延迟,可以进行有限次数的轮询:

async function waitForPaid(orderNo) {
  const intervals = [1000, 1500, 2500, 4000];

  for (const delay of intervals) {
    const order = await queryOrder(orderNo);

    if (order.status === 'PAID') {
      return true;
    }

    if (order.status === 'CLOSED') {
      return false;
    }

    await new Promise(resolve => setTimeout(resolve, delay));
  }

  return null;
}

轮询结束后仍无法确认结果时,不要直接显示“支付失败”。更合适的提示是“支付结果确认中”,同时提供“刷新状态”和“重新支付”按钮。

取消和异常处理

用户取消支付宝支付后,订单通常仍是 UNPAID 或 PENDING 状态。前端应保留订单,并允许用户重新发起支付:

async function handlePaymentInterrupt(orderNo, error) {
  const order = await queryOrder(orderNo);

  if (order.status === 'PAID') {
    showPaySuccess(orderNo);
    return;
  }

  if (isUserCancel(error)) {
    showToast('支付已取消');
    return;
  }

  showToast('暂未确认支付结果,请刷新后查看');
}

不要仅根据错误码立即关闭订单。未支付订单应由服务端按照超时规则关闭。

注意事项

  • 不要默认使用小红书开放平台未明确支持的外部跳转方式,应以当前平台文档和审核规则为准。
  • 支付宝订单创建、金额计算、签名和异步通知验签都应在服务端完成。
  • 前端只传业务订单号,不传可能被篡改并直接生效的支付金额。
  • 支付接口需要支持幂等,避免同一业务订单因重复点击产生多次履约。
  • 收银台按钮需要防止重复点击,但不能只依靠前端锁定。
  • H5 收银台域名、接口域名和回跳地址需要提前加入白名单,并使用 HTTPS。
  • 不要在日志、页面参数或埋点中记录签名、令牌和完整支付凭证。
  • 支付结果以服务端订单状态为准,前端回调只负责触发查询和改善交互。
  • 必须在 Android、iOS 和不同客户端版本上进行真机测试,重点检查唤起、取消、返回、断网和重复支付场景。

备注:内容仅供参考。