h5端实现调起微信app支付

时间:2025-04-27 08:56:15

在H5端实现调起微信APP支付需要通过一系列步骤,包括配置微信支付、前端调用微信支付接口、生成支付订单、调用支付接口等。下面是详细的步骤和代码示例:

1. 配置微信支付

首先需要在微信支付商户平台上进行配置,获取商户号(MchID)和API密钥(API Key),并且确保已开通支付功能。

2. 前端代码示例

前端代码主要是生成支付订单并调用微信支付接口。这里假设你使用的是框架,其他框架类似。

HTML和JavaScript代码:
<!DOCTYPE html>
<html>
<head>
  <title>微信支付</title>
  <script src="/open/js/jweixin-1.6."></script>
</head>
<body>
  <button >微信支付</button>

  <script>
    // 微信配置
    ({
      debug: false,
      appId: 'yourAppId', // 必填,公众号的唯一标识
      timestamp: 0, // 必填,生成签名的时间戳
      nonceStr: '', // 必填,生成签名的随机串
      signature: '', // 必填,签名
      jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表
    });

    // 获取支付订单参数
    function getPaymentParams() {
      return fetch('/getPaymentParams', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: ({
          orderId: 'yourOrderId'
        })
      })
      .then(response => ());
    }

    // 调用微信支付
    function invokeWeChatPay(params) {
      ({
        timestamp: , // 支付签名时间戳
        nonceStr: , // 支付签名随机串,不长于 32 位
        package: , // 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=***
        signType: , // 签名类型,默认为'SHA1',使用新版支付需传入'MD5'
        paySign: , // 支付签名
        success: function (res) {
          // 支付成功后的回调函数
          alert('支付成功');
        },
        fail: function (res) {
          // 支付失败后的回调函数
          alert('支付失败');
        }
      });
    }

    ('payBtn').addEventListener('click', function() {
      getPaymentParams().then(params => {
        invokeWeChatPay(params);
      });
    });
  </script>
</body>
</html>
代码说明:
  1. 微信配置:使用方法配置微信JS SDK,包括appIdtimestampnonceStrsignature等。
  2. 获取支付订单参数:通过调用后台接口获取支付订单参数,包括timestampnonceStrpackagesignTypepaySign
  3. 调用微信支付:使用方法调起微信支付,传入支付订单参数。

3. 后端代码示例

后端代码负责生成支付订单并返回给前端。以下是的示例代码。

代码:
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const crypto = require('crypto');

const app = express();
(());

const appId = 'yourAppId';
const mchId = 'yourMchId';
const apiKey = 'yourApiKey';

// 生成支付订单参数
('/getPaymentParams', (req, res) => {
  const orderId = ;
  
  // 统一下单接口
  const unifiedOrderUrl = '/pay/unifiedorder';
  
  const nonceStr = (16).toString('hex');
  const timestamp = (() / 1000).toString();
  const body = '商品描述';
  const outTradeNo = orderId;
  const totalFee = 1; // 订单金额,单位为分
  const spbillCreateIp = ;
  const notifyUrl = '/pay/notify';
  const tradeType = 'JSAPI';
  const openId = 'yourOpenId'; // 用户的OpenID

  // 签名
  const params = {
    appid: appId,
    mch_id: mchId,
    nonce_str: nonceStr,
    body,
    out_trade_no: outTradeNo,
    total_fee: totalFee,
    spbill_create_ip: spbillCreateIp,
    notify_url: notifyUrl,
    trade_type: tradeType,
    openid: openId
  };
  
  const stringA = (params).sort().map(key => `${key}=${params[key]}`).join('&');
  const stringSignTemp = `${stringA}&key=${apiKey}`;
  const sign = ('md5').update(stringSignTemp).digest('hex').toUpperCase();
  
  const formData = `<xml>
    <appid>${appId}</appid>
    <mch_id>${mchId}</mch_id>
    <nonce_str>${nonceStr}</nonce_str>
    <sign>${sign}</sign>
    <body>${body}</body>
    <out_trade_no>${outTradeNo}</out_trade_no>
    <total_fee>${totalFee}</total_fee>
    <spbill_create_ip>${spbillCreateIp}</spbill_create_ip>
    <notify_url>${notifyUrl}</notify_url>
    <trade_type>${tradeType}</trade_type>
    <openid>${openId}</openid>
  </xml>`;

  request({
    url: unifiedOrderUrl,
    method: 'POST',
    body: formData
  }, (err, response, body) => {
    if (err) {
      (500).send(err);
    } else {
      // 解析微信返回的XML数据
      const prepayId = /<prepay_id><!\[CDATA\[(.*)\]\]><\/prepay_id>/.exec(body)[1];
      const paySign = ('md5').update(`appId=${appId}&nonceStr=${nonceStr}&package=prepay_id=${prepayId}&signType=MD5&timeStamp=${timestamp}&key=${apiKey}`).digest('hex').toUpperCase();

      ({
        timestamp,
        nonceStr,
        package: `prepay_id=${prepayId}`,
        signType: 'MD5',
        paySign
      });
    }
  });
});

(3000, () => {
  ('Server is running on port 3000');
});
代码说明:
  1. 生成支付订单参数:接收前端传来的订单ID,生成支付订单参数,包括nonceStrtimestampoutTradeNototalFeespbillCreateIpnotifyUrltradeTypeopenId
  2. 签名:对支付参数进行签名,生成sign
  3. 调用统一下单接口:向微信支付的统一下单接口发送请求,获取prepayId
  4. 返回支付参数:将prepayIdtimestampnonceStrpackagesignTypepaySign返回给前端。

4. 回调处理

支付成功后,微信会回调商户服务器的通知URL。商户服务器需要对通知进行处理,并更新订单状态。

回调处理示例:
const xmlParser = require('express-xml-bodyparser');

// 微信支付回调通知
('/pay/notify', xmlParser({trim: false, explicitArray: false}), (req, res) => {
  const xml = ;
  
  const params = {
    appid: ,
    mch_id: xml.mch_id,
    nonce_str: xml.nonce_str,
    result_code: xml.result_code,
    openid: ,
    total_fee: xml.total_fee,
    out_trade_no: xml.out_trade_no
  };
  
  const stringA = (params).sort().map(key => `${key}=${params[key]}`).join('&');
  const stringSignTemp = `${stringA}&key=${apiKey}`;
  const sign = ('md5').update(stringSignTemp).digest('hex').toUpperCase();
  
  if (sign === ) {
    // 验签成功,处理业务逻辑
    if (xml.result_code === 'SUCCESS') {
      // 支付成功,更新订单状态
      // TODO: 更新数据库订单状态
      ('<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>');
    } else {
      ('<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>');