PAYATHON 2026

支付宝小程序 my.tradePay 支付后如何避免直接退出

支付阿杰

结论

“谢谢您的消费”是支付宝收银台流程中的页面,小程序通常不能修改这个页面,也无法控制页面上的返回按钮。支付后小程序直接退出,通常不是支付结果出了问题,而是调用 my.tradePay 时,页面栈里没有可返回的业务页面,或者支付在 app.js 的 onLaunch、页面的 onLoad / onShow 中被自动触发。

建议先进入正常的小程序业务页面,再由用户操作发起支付。支付结果应在 my.tradePay 回调中处理,并跳转到支付结果页。收银台的返回动作不应承担业务跳转功能。

常见原因

支付调用得太早

如果在 App.onLaunch 中直接调用 my.tradePay,打开收银台时,小程序可能还没有建立稳定的页面栈。支付完成并关闭收银台后,小程序就可能直接退出。

页面是临时入口

如果用户通过支付二维码、外部链接或其他特殊入口启动小程序,并立即进入支付流程,收银台可能成为当前交互链路中唯一明显的页面。收银台关闭后,没有合适的业务页面可供恢复。

在 onShow 中反复拉起支付

从支付宝收银台返回小程序时,页面可能再次触发 onShow。如果没有判断当前状态,onShow 会再次执行 my.tradePay,可能导致收银台被重复拉起、页面状态异常,或者出现不符合预期的退出行为。

推荐处理方式

1. 先准备支付页面和结果页面

例如:

pages/order/detail
pages/pay/result

调用支付前,应先让用户进入 pages/order/detail,不要在 app.js 中直接发起支付。

2. 通过用户点击调用 my.tradePay

Page({
  data: {
    paying: false
  },

  async handlePay() {
    if (this.data.paying) {
      return;
    }

    this.setData({
      paying: true
    });

    try {
      // 应由服务端创建支付宝交易,并返回 tradeNO。
      const tradeNO = await this.createTrade();

      my.tradePay({
        tradeNO,

        success: (res) => {
          if (String(res.resultCode) === '9000') {
            my.redirectTo({
              url: `/pages/pay/result?status=success&tradeNO=${encodeURIComponent(tradeNO)}`
            });
            return;
          }

          // 非 9000 不一定代表订单最终未支付,
          // 仍建议向服务端查询订单状态。
          this.queryAndHandleOrder(tradeNO, res.resultCode);
        },

        fail: (err) => {
          console.error('my.tradePay 调用失败:', err);

          my.redirectTo({
            url: '/pages/pay/result?status=unknown'
          });
        },

        complete: () => {
          this.setData({
            paying: false
          });
        }
      });
    } catch (err) {
      this.setData({
        paying: false
      });

      my.showToast({
        type: 'fail',
        content: '创建支付订单失败'
      });
    }
  },

  createTrade() {
    // 示例:替换成项目实际的服务端请求。
    return Promise.resolve('服务端返回的 tradeNO');
  },

  queryAndHandleOrder(tradeNO, resultCode) {
    my.redirectTo({
      url:
        `/pages/pay/result?status=processing` +
        `&tradeNO=${encodeURIComponent(tradeNO)}` +
        `&resultCode=${encodeURIComponent(String(resultCode || ''))}`
    });
  }
});

如果项目采用 orderStr 模式,应按当前接入方式传入 orderStr,不要默认一定会有 tradeNO:

my.tradePay({
  orderStr: '服务端返回的订单字符串',
  success(res) {
    console.log(res.resultCode);
  },
  fail(err) {
    console.error(err);
  }
});

可用参数由小程序当前使用的支付宝支付产品和接入方式决定。

3. 在结果页向服务端确认订单

客户端回调只适合用来改善页面体验,不能作为最终到账依据。结果页应使用业务订单号向服务端查询支付状态:

Page({
  onLoad(query) {
    this.orderNo = query.orderNo;
    this.loadOrderStatus();
  },

  async loadOrderStatus() {
    try {
      // 替换成项目实际接口。
      const order = await this.queryOrderFromServer(this.orderNo);

      this.setData({
        status: order.payStatus
      });
    } catch (err) {
      my.showToast({
        type: 'none',
        content: '订单状态查询失败,请稍后重试'
      });
    }
  },

  queryOrderFromServer(orderNo) {
    return Promise.resolve({
      orderNo,
      payStatus: 'PAID'
    });
  }
});

服务端应根据支付宝异步通知或主动查询接口确认支付结果,不能只凭客户端返回的 resultCode 发货或更新订单。

如果必须自动发起支付

如果确实需要从特定入口自动拉起支付,应先等承载页面加载完成,再设置一次性状态,避免页面恢复时重复调用:

Page({
  data: {
    paymentStarted: false
  },

  onReady() {
    if (this.data.paymentStarted) {
      return;
    }

    this.setData({
      paymentStarted: true
    });

    this.startPayment();
  },

  startPayment() {
    my.tradePay({
      tradeNO: '服务端返回的 tradeNO',

      success: (res) => {
        my.redirectTo({
          url: `/pages/pay/result?resultCode=${encodeURIComponent(
            String(res.resultCode || '')
          )}`
        });
      },

      fail: () => {
        my.redirectTo({
          url: '/pages/pay/result?status=unknown'
        });
      }
    });
  }
});

更稳妥的做法是先展示订单确认页,等用户点击“立即支付”后再调用支付 API。

注意事项

  • 不要尝试控制或替换支付宝收银台的“谢谢您的消费”页面。
  • 不要在 App.onLaunch 中直接调用 my.tradePay。
  • 在 onShow 中发起支付要谨慎,因为从收银台返回时可能再次触发该生命周期。
  • 调用支付前,页面栈中至少要有一个正常的小程序业务页面。
  • 使用 paying、paymentStarted 等状态避免重复提交。
  • 支付成功后可以使用 my.redirectTo 进入结果页。如果结果页是 tabBar 页面,应改用 my.switchTab。
  • 不要仅凭客户端回调认定订单已经支付,最终支付结果应由服务端确认。
  • 如果调整调用时机和页面栈后仍然会退出,需要结合小程序的启动入口、支付接入模式、基础库环境和真机日志继续排查。仅凭“谢谢您的消费”页面,无法判断问题来自支付宝客户端。

备注:内容仅供参考。