微信支付

person 少陵野老    watch_later 2024-07-10 20:53:28
visibility 145    class 微信支付,小程序    bookmark 专栏

实现微信小程序的微信支付涉及到小程序端的调用和后端服务器的处理。下面是一个完整的实现流程,包括小程序端的实现、Node.js后端的实现以及支付回调的处理。

1. 小程序端实现

在小程序端实现微信支付,主要包括获取用户授权、调用统一下单接口发起支付请求、处理支付结果等步骤。

a. 获取用户授权及登录

首先,确保用户已经授权登录并获取到用户的 openid,通常在小程序启动时获取。可以使用微信提供的 wx.login 接口获取用户登录凭证 code,然后使用 wx.request 发送到后端进行换取 openid

示例代码(小程序端):

// 获取用户登录凭证 code
wx.login({
  success(res) {
    if (res.code) {
      // 将 code 发送到后端获取 openid
      wx.request({
        url: 'https://your-backend-server.com/login',
        method: 'POST',
        data: {
          code: res.code
        },
        success(response) {
          const openid = response.data.openid;
          // 将 openid 存储在全局变量或者缓存中
        },
        fail(err) {
          console.error('获取openid失败:', err);
        }
      });
    } else {
      console.error('登录失败:', res);
    }
  },
  fail(err) {
    console.error('wx.login调用失败:', err);
  }
});

b. 统一下单并发起支付

使用微信提供的统一下单接口 https://api.mch.weixin.qq.com/pay/unifiedorder,向微信服务器发送支付请求,并获取到预支付交易会话标识 prepay_id

示例代码(小程序端):

// 发起支付请求
wx.request({
  url: 'https://your-backend-server.com/prepay',
  method: 'POST',
  data: {
    openid: '用户openid',
    total_fee: 1, // 支付金额,单位为分
    body: '订单支付',
    out_trade_no: 'your_out_trade_no' // 商户订单号,需保证唯一性
  },
  success(res) {
    console.log('预支付结果:', res.data);
    // 调起支付界面
    wx.requestPayment({
      timeStamp: res.data.timeStamp,
      nonceStr: res.data.nonceStr,
      package: 'prepay_id=' + res.data.prepay_id,
      signType: 'MD5',
      paySign: res.data.paySign,
      success(payRes) {
        console.log('支付成功:', payRes);
        // 支付成功后的逻辑处理
      },
      fail(payRes) {
        console.error('支付失败:', payRes);
        // 支付失败后的逻辑处理
      }
    });
  },
  fail(err) {
    console.error('发起支付请求失败:', err);
  }
});

2. Node.js 后端实现

在后端使用 Node.js 实现统一下单接口和支付结果通知处理,主要包括生成签名、调用微信支付API等。

a. 生成签名

在后端生成用于验证身份和请求合法性的签名。

示例代码(Node.js):

const crypto = require('crypto');

function getSign(params, key) {
  const sortedParams = Object.keys(params).sort().reduce((acc, key) => {
    acc[key] = params[key];
    return acc;
  }, {});

  const stringToSign = Object.keys(sortedParams).map(key => `${key}=${sortedParams[key]}`).join('&') + `&key=${key}`;
  return crypto.createHash('md5').update(stringToSign, 'utf8').digest('hex').toUpperCase();
}

b. 统一下单接口

实现后端接口,调用微信支付的统一下单接口,返回预支付数据给小程序端。

示例代码(Node.js,使用 Express 框架):

const express = require('express');
const request = require('request');
const bodyParser = require('body-parser');

const app = express();
const PORT = 3000;

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// 处理小程序发起预支付请求
app.post('/prepay', (req, res) => {
  const { openid, total_fee, body, out_trade_no } = req.body;

  const params = {
    appid: 'your_appid',
    mch_id: 'your_mch_id',
    nonce_str: generateNonceString(),
    body: body,
    out_trade_no: out_trade_no,
    total_fee: total_fee,
    spbill_create_ip: '127.0.0.1', // 支付终端IP,可以自行获取
    notify_url: 'https://your-backend-server.com/pay/callback', // 支付结果回调通知地址
    trade_type: 'JSAPI',
    openid: openid
  };

  params.sign = getSign(params, 'your_merchant_key');

  // 发起统一下单请求
  request.post({
    url: 'https://api.mch.weixin.qq.com/pay/unifiedorder',
    body: params,
    json: true
  }, (err, response, body) => {
    if (err) {
      console.error('统一下单接口调用失败:', err);
      res.status(500).json({ message: '支付接口调用失败' });
    } else {
      console.log('统一下单成功:', body);
      const { timeStamp, nonceStr, sign, prepay_id } = body.xml;
      const paySign = getSign({ appId: 'your_appid', timeStamp, nonceStr, package: `prepay_id=${prepay_id}`, signType: 'MD5' }, 'your_merchant_key');

      res.json({
        timeStamp: timeStamp,
        nonceStr: nonceStr,
        package: `prepay_id=${prepay_id}`,
        signType: 'MD5',
        paySign: paySign
      });
    }
  });
});

// 启动服务器
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

// 生成随机字符串
function generateNonceString() {
  return Math.random().toString(36).substr(2, 15);
}

3. 支付结果回调处理

当用户支付成功后,微信服务器会向预先设置的 notify_url 发送支付结果通知。在后端服务器接收并验证通知的签名,处理订单状态更新等业务逻辑。

示例代码(Node.js,Express 框架):

app.post('/pay/callback', (req, res) => {
  // 获取微信支付通知数据
  const xmlData = req.body;

  // 验证签名
  const { sign, ...params } = xmlData;
  const calculatedSign = getSign(params, 'your_merchant_key');
  if (calculatedSign !== sign) {
    console.error('签名验证失败');
    return res.status(400).send('签名验证失败');
  }

  // 处理支付结果逻辑,更新订单状态等
  console.log('支付成功:', params);
  // 返回通知给微信服务器
  res.set('Content-Type', 'text/xml');
  res.send('<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>');
});

注意事项

  • 确保小程序和后端的所有请求和通信都使用HTTPS协议。
  • 统一下单接口的参数和签名生成需要严格按照微信支付的要求进行。
  • 支付结果回调处理要保证安全性和可靠性,及时响应微信服务器的通知。

通过以上步骤,您可以实现微信小程序的微信支付功能,并在后端服务器端处理支付结果。具体实现中,根据实际需求和微信支付官方文档进行详细调整和优化。

评论区
评论列表
menu