收藏
回答

用云函数实现JSAPI微信支付,使用模拟器调试成功,真机调试失败,怎么回事?

1、两者的OpenID获取方式不同问题

我的预支付用的云函数payment如下:

const cloud = require('wx-server-sdk');
const {
  WXPay,
  WXPayUtil
} = require('wx-js-utils');

cloud.init();

const appId = 'wx***'// 小程序appid
const mchId = '***'// 商户号
const key = '***'// 商户密钥
const timeout = 10000// 超时时间

let wxpay = new WXPay({
  appId,
  mchId,
  key,
  timeout10000,
  signType'MD5',
  useSandboxfalse // 不使用沙箱环境
});

exports.main = async (event, context) => {
  const curTime = Date.now();
  // 存放订单号
  let orderCode = '';

  // 6位随机数(加在时间戳后面)
  for (var i = 0; i < 6; i++) {
    orderCode += Math.floor(Math.random() * 10);
  }

  // 时间戳(用来生成订单号)
  orderCode = 'D' + new Date().getTime() + orderCode;
  const tradeNo = orderCode;
  const body = '测试订单'// 订单商品名称
  const spbill_create_ip = '127.0.0.1'// 发起支付的IP
  const notify_url = 'http://www.qq.com'// 回调地址
  const total_fee = event.price * 100// 支付金额,单位为分
  var time_stamp = '' + Math.ceil(Date.now() / 1000);
  
  console.log("Time stamp: " + time_stamp)
  const out_trade_no = `${tradeNo}`;
  console.log(event.openId)
  let orderParam = {
    body,
    spbill_create_ip,
    notify_url,
    out_trade_no,
    total_fee,
    openid: event.openId,
    trade_type'JSAPI',
    timeStamp: time_stamp,
  };
  const {
    return_code,
    result_code,
    ...restData
  } = await wxpay.unifiedOrder(orderParam); // 统一下单
  console.log("#RETURN_CODE")
  console.log(return_code)
  if (return_code == 'SUCCESS') {
    console.log("#RESTDATA")
    console.log(restData)
    const {
      prepay_id,
      nonce_str
    } = restData;
    const sign = WXPayUtil.generateSignature({
      appId,
      nonceStr: nonce_str,
      package`prepay_id=${prepay_id}`,
      signType'MD5',
      timeStamp: time_stamp
    }, key); // 签名

    return {
      code0,
      data: {
        out_trade_no: out_trade_no,
        time_stamp: time_stamp,
        ...restData,
        sign: sign
      }
    }
  }
  return {
    code-1
  }
};


我的获取OpenID用的云函数getopenid如下:

// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init()

// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  return {
    event,
    openid: wxContext.OPENID,
    appid: wxContext.APPID,
    unionid: wxContext.UNIONID,
  }

支付页面的代码如下:

Page({
    data: {
        price0.01,
        openid''
    },
    onLoad() {
        this.getOpenid()
    },
    // 定义调用云函数获取openid
    getOpenid() {
        let page = this;
        wx.cloud.callFunction({
            name'getopenid',
            completeres => {
                console.log('openid--', res.result)
                var openid = res.result.openid
                page.setData({
                    openid: openid
                })
            }
        })
    },
    onInput(event) {
        this.getOpenid()
        this.setData({
            price: event.detail.value
        });
    },
    pay() {
        const price = parseFloat(this.data.price).toFixed(2);
        wx.showLoading({
            title'请稍候...'
        });
        var openid = this.data.openid
        console.log("OpenID:" + openid)
        // 可以将 res 发送给i后台解码出 unionId
        wx.cloud.callFunction({
            name'payment'// 调用payment函数
            data: {
                price: price,
                openId: openid
            }, // 支付金额
            success(res) => {
                wx.hideLoading();
                console.log(res)
                const {
                    result
                } = res;
                const {
                    code,
                    data
                } = result;

                if (res.result.code != 0) {
                    wx.showModal({
                        title'提示',
                        content"支付失败",
                        showCancelfalse
                    });
                    return;
                }
                wx.requestPayment({
                    timeStamp: data.time_stamp,
                    nonceStr: data.nonce_str,
                    package`prepay_id=${data.prepay_id}`,
                    signType'MD5',
                    paySign: data.sign,
                    total_fee: price,
                    success() => {
                        wx.showToast({
                            title'支付成功'
                        });
                    }
                });
            },
            fail(res) => {
                wx.hideLoading();
                console.log('FAIL');
                console.log(res);
            }
        });
    }
})


对于支付页面代码中的getOpenid()中的var openid = res.result.openid,仅在模拟器调试中有效,即在点击支付后,模拟器弹出二维码,手机扫描二维码后可顺利支付;但是如果在真机中运行,openid将会是undefined,导致支付失败。在真机中,只有把res.result.openid改为res.result.userInfo.openId,才能获取到openid,但是由于接下来的第2个问题,真机依然无法顺利支付。

2、出现了云函数payment的回调success中的res异常等于之前云函数getopenid的回调中的complete的res的现象,尽管这两个云函数内部没有任何联系。这个问题在真机调试时必然发生,在模拟器调试时可能发生。在模拟器调试时一旦打开云函数本地调试器,该现象即消失,payment的res恢复正常;在未知情形下,该现象会重新出现。这个现象导致了接下来的data对象为undefined,导致支付失败。


总之,这两个问题完全在我的意料之外,我认为外部的不确定性因素对程序无法正常运行有最为重要的影响。我应该怎么解决这个问题,或者采取更加可靠的解决方案?

最后一次编辑于  2021-01-23
回答关注问题邀请回答
收藏

1 个回答

  • 跨商通
    跨商通
    2021-01-23

    1、小程序端的拉起支付并不需要用到openid。

    2、getOpenid里,加一个:async(event,context),即可。

    2021-01-23
    有用
    回复
登录 后发表内容
问题标签