微信小程序对接微信支付的步骤

一、前期准备工作

  1. 注册微信小程序账号
    • 访问微信公众平台(https://mp.weixin.qq.com/),点击 “立即注册”,选择账号类型为 “小程序”。
    • 按照系统提示填写邮箱、密码等注册信息,完成注册流程。注册成功后,会获得小程序的 AppID,这是小程序的唯一标识,在后续对接微信支付等操作中会频繁用到。
  2. 完成小程序认证
    • 只有经过认证的小程序才可以申请微信支付。认证方式主要有微信认证和快速认证两种。
    • 微信认证:适用于企业、政府、媒体、其他组织类型的小程序。认证时需要提交营业执照、法人身份证等相关资料,同时需支付 300 元 / 次的认证费用。认证审核通常在 1 – 5 个工作日内完成。
    • 快速认证:若小程序主体已在微信开放平台完成认证,可通过快速认证的方式免去再次提交资料和支付费用的环节,直接复用开放平台的认证资质。
  3. 申请微信支付商户号
    • 登录小程序后台,在左侧菜单栏中找到 “微信支付” 选项,点击进入。
    • 点击 “申请接入” 按钮,可选择申请新的商户号或绑定已有商户号。
    • 申请新商户号
      • 填写企业基本信息,包括企业名称、营业执照注册号、法人姓名及身份证号码等。确保信息准确无误,否则会影响审核进度。
      • 提供企业对公银行账户信息,用于接收微信支付的结算款项。微信支付会向该对公账户打一笔随机金额的验证款,收到款项后,需在商户平台输入该金额完成验证。
      • 提交申请后,微信支付会对提交的资料进行审核,审核时间一般为 1 – 3 个工作日。审核通过后,会收到包含商户号、商户平台登录账号和密码等信息的邮件通知。
    • 绑定已有商户号:若企业已有微信支付商户号,且该商户号支持小程序支付,可在小程序后台直接绑定。绑定过程中需输入商户号及相关验证信息,完成绑定后即可使用该商户号进行小程序支付。

二、配置相关信息

  1. 配置小程序密钥(AppSecret)
    • 在小程序后台的 “设置” – “开发设置” 页面中,点击 “生成” 按钮。
    • 管理员使用微信扫描出现的二维码进行身份验证。验证通过后,系统会随机生成一个 AppSecret。AppSecret 是小程序的重要安全信息,用于与微信服务器进行交互验证,如获取用户的 openid 等操作。务必妥善保管,不要将其明文存储在服务器或泄露给他人。
  2. 设置商户平台密钥和下载证书
    • 使用申请微信支付时获得的商户平台登录账号和密码,登录微信支付商户平台(weixin.qq.com)。
    • 在商户平台的 “账户中心” – “API 安全” 页面中,进行以下操作:
      • 设置 API 密钥:点击 “设置密钥” 按钮,按照要求设置一个 32 位的密钥。该密钥用于对微信支付相关接口请求和响应数据进行签名加密,保障数据传输的安全性和完整性。设置完成后,务必牢记该密钥,因为后续无法直接查看,若遗忘需重新设置。
      • 下载证书:为了保证通信安全,微信支付要求商户在调用某些接口时使用证书。在 “API 安全” 页面中,点击 “证书下载” 按钮,按照提示进行操作,下载商户证书。证书文件一般为.p12 格式,下载后需妥善保存,在后续开发中配置到服务器相应位置。
  1. 配置 Https 服务器
    • 小程序发起的所有网络请求都必须使用 Https 协议,因此需要为小程序的后端服务器配置 Https。
    • 获取 SSL 证书:可以从正规的证书颁发机构(CA)购买 SSL 证书,如阿里云、腾讯云等云服务提供商也提供 SSL 证书的申请和购买服务,部分情况下还提供免费的 SSL 证书供用户选择。
    • 安装 SSL 证书到服务器:根据服务器的类型和操作系统,按照相应的教程将购买或申请到的 SSL 证书安装到服务器上。安装完成后,通过访问服务器地址,确认网址前缀变为 “https://”,且浏览器地址栏显示安全锁标志,表明 Https 配置成功。

三、编写代码实现对接

  1. 获取用户 openid
    • 在小程序端,使用login接口获取临时登录凭证 code。代码示例如下:

 

wx.login({

success(res) {

if (res.code) {

// 将code发送到服务器

wx.request({

url: ‘https://your – server – url.com/getOpenid’,

method: ‘POST’,

data: {

code: res.code

},

success: function (serverRes) {

console.log(serverRes.data.openid);

}

});

} else {

console.log(‘登录失败!’ + res.errMsg);

}

}

});

  • 在服务器端,接收到小程序发送的 code 后,通过向微信官方提供的接口(https://api.weixin.qq.com/sns/jscode2session)发送请求,换取用户的 openid。请求参数包括小程序的 AppID、AppSecret 以及接收到的 code。示例代码(以 js 和 Express 框架为例):

 

const express = require(‘express’);

const app = express();

const request = require(‘request’);

app.post(‘/getOpenid’, (req, res) => {

const code = req.body.code;

const appId = ‘your – appid’;

const appSecret = ‘your – appsecret’;

const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appId}&secret=${appSecret}&js_code=${code}&grant_type=authorization_code`;

request(url, (error, response, body) => {

if (!error && response.statusCode === 200) {

const data = JSON.parse(body);

res.send({ openid: data.openid });

} else {

res.send({ error: ‘获取openid失败’ });

}

});

});

const port = 3000;

app.listen(port, () => {

console.log(`Server is running on port ${port}`);

});

  1. 统一下单
    • 商户服务器需要调用微信支付的统一下单接口(https://api.mch.weixin.qq.com/pay/unifiedorder)来生成预支付交易会话标识(prepay_id)。
    • 统一下单接口的请求参数众多,常见的参数包括:
      • appid:小程序的 AppID。
      • mch_id:微信支付商户号。
      • nonce_str:随机字符串,长度要求 32 位以内,用于防止重复请求。可通过程序生成随机字符串,例如在 JavaScript 中可以使用random().toString(36).substr(2, 32)生成。
      • sign_type:签名类型,支持 MD5 和 HMAC – SHA256 两种,一般推荐使用 HMAC – SHA256。
      • body:商品或服务的简要描述,例如 “商品名称 – 规格型号”。
      • out_trade_no:商户系统内部的订单号,要求在商户系统中唯一,建议使用时间戳加随机数等方式生成,如now() + Math.floor(Math.random() * 1000000)。
      • total_fee:订单总金额,单位为分。例如,订单金额为 10 元,此处应填写 1000。
      • spbill_create_ip:用户端实际 IP 地址,可通过服务器获取请求的客户端 IP。
      • notify_url:支付结果通知回调地址,微信支付在用户支付完成后会向该地址发送支付结果通知。需确保该地址可外网访问,且地址格式正确,例如 “https://your – server – com/pay/notify”。
      • trade_type:交易类型,小程序支付固定为 “JSAPI”。
      • openid:用户的 openid,通过上述获取用户 openid 的步骤得到。
    • 示例代码(以 PHP 为例):

 

<?php

$appid = ‘your – appid’;

$mch_id = ‘your – mch – id’;

$nonce_str = md5(uniqid(rand(), true));

$body = ‘商品描述’;

$out_trade_no = date(‘YmdHis’) . rand(1000, 9999);

$total_fee = 1000;

$spbill_create_ip = $_SERVER[‘REMOTE_ADDR’];

$notify_url = ‘https://your – server – url.com/pay/notify’;

$trade_type = ‘JSAPI’;

$openid = ‘user – openid’;

// 构造请求参数数组

$params = [

‘appid’ => $appid,

‘mch_id’ => $mch_id,

‘nonce_str’ => $nonce_str,

‘body’ => $body,

‘out_trade_no’ => $out_trade_no,

‘total_fee’ => $total_fee,

‘spbill_create_ip’ => $spbill_create_ip,

‘notify_url’ => $notify_url,

‘trade_type’ => $trade_type,

‘openid’ => $openid

];

// 计算签名

$key = ‘your – api – key’;

$stringA = ”;

foreach ($params as $k => $v) {

if ($v!= ” && $k!=’sign’) {

$stringA.= $k.’=’.$v.’&’;

}

}

$stringA = rtrim($stringA, ‘&’);

$stringSignTemp = $stringA.’&key=’.$key;

$sign = strtoupper(md5($stringSignTemp));

$params[‘sign’] = $sign;

// 将参数转换为XML格式

$xml = ‘<xml>’;

foreach ($params as $k => $v) {

$xml.= ‘<‘.$k.’>’.$v.'</’.$k.’>’;

}

$xml.= ‘</xml>’;

// 发起统一下单请求

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, ‘https://api.mch.weixin.qq.com/pay/unifiedorder’);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($ch, CURLOPT_POST, 1);

curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);

$response = curl_exec($ch);

curl_close($ch);

// 解析返回结果

libxml_disable_entity_loader(true);

$responseObj = simplexml_load_string($response, ‘SimpleXMLElement’, LIBXML_NOCDATA);

$prepay_id = $responseObj->prepay_id;

?>

  1. 再次签名
    • 服务器接收到微信支付统一下单接口返回的结果后,需要从中获取 prepay_id,并根据 prepay_id 等参数按照微信支付的签名规则进行再次签名,生成 paySign。
    • 参与签名的参数包括:
      • appId:小程序的 AppID。
      • timeStamp:当前时间戳,以秒为单位,可通过floor(Date.now() / 1000)在 JavaScript 中获取,或使用time()函数在 PHP 中获取。
      • nonceStr:随机字符串,与统一下单时的随机字符串保持一致或重新生成一个新的。
      • package:固定值 “prepay_id=prepay_id 的值”,其中 prepay_id 的值为统一下单接口返回的 prepay_id。
      • signType:签名类型,与统一下单时的签名类型保持一致。
    • 示例代码(以 JavaScript 为例):

 

const appId = ‘your – appid’;

const timeStamp = Math.floor(Date.now() / 1000).toString();

const nonceStr = Math.random().toString(36).substr(2, 32);

const packageStr = `prepay_id=${prepay_id}`;

const signType = ‘HMAC – SHA256’;

const key = ‘your – api – key’;

const stringA = `appId=${appId}&nonceStr=${nonceStr}&package=${packageStr}&signType=${signType}&timeStamp=${timeStamp}`;

const stringSignTemp = stringA + ‘&key=’ + key;

const crypto = require(‘crypto’);

const hmac = crypto.createHmac(‘sha256’, key);

hmac.update(stringSignTemp);

const paySign = hmac.digest(‘hex’).toUpperCase();

  1. 小程序调起支付
    • 在小程序端,调用requestPayment接口来调起微信支付界面,让用户进行支付操作。
    • requestPayment接口需要传入以下参数:
      • appId:小程序的 AppID。
      • timeStamp:服务器生成的时间戳字符串。
      • nonceStr:随机字符串。
      • package:服务器生成的 package 字符串,格式为 “prepay_id=prepay_id 的值”。
      • signType:签名类型。
      • paySign:服务器生成的签名。
    • 代码示例:

 

wx.requestPayment({

timeStamp: timeStamp,

nonceStr: nonceStr,

package: packageStr,

signType:’sha256′,

paySign: paySign,

success(res) {

console.log(‘支付成功’, res);

},

fail(err) {

console.log(‘支付失败’, err);

}

});

四、支付结果处理

  1. 接收支付通知
    • 微信支付系统在用户支付完成后,会向商户服务器在统一下单时设置的notify_url地址发送支付结果通知。通知内容为 XML 格式的数据,包含了订单号、支付状态、支付金额等关键信息。
    • 商户服务器需要在notify_url对应的接口中接收并解析该 XML 数据,验证签名的正确性,以确保通知数据的真实性和完整性。示例代码(以 js 和 Express 框架为例):

 

const express = require(‘express’);

const app = express();

const xml2js = require(‘xml2js’);

app.post(‘/pay/notify’, (req, res) => {

let xmlData = ”;

req.on(‘data’, (chunk) => {

xmlData += chunk;

});

req.on(‘end’, async () => {

const parser = new xml2js.Parser();

const result = await parser.parseStringPromise(xmlData);

const sign = result.xml.sign[0];

// 重新计算签名进行验证

const params = result.xml;

delete params.sign;

const stringA = [];

for (const key in params) {

if (params[key] && params[key].length > 0) {

stringA.push(`${key}=${params[key][0]}`);

}

}

stringA.sort();

const stringSignTemp = stringA.join(‘&’) + ‘&key=your – api – key’;

const crypto = require(‘crypto’);

const hmac = crypto.createHmac(‘sha256’, ‘your – api – key’);

hmac.update(stringSignTemp);

const newSign = hmac.digest(‘hex’).toUpperCase();

if (newSign === sign) {

const resultCode = result.xml.result_code[0];

const outTradeNo = result.xml.out_trade_no[0];

if (resultCode === ‘SUCCESS’) {

// 更新订单状态为已支付等业务逻辑处理

console.log(‘支付成功,订单号:’, outTradeNo);

} else {

console.log(‘支付失败,订单号:’, outTradeNo);

}

} else {

console.log(‘签名验证失败’);

}

res.send(‘<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>’);

});

});

const port = 3000;

app.listen(port, () => {

console.log(`Server is running on port ${port}`);

});

  1. 查询支付结果
    • 由于网络等原因,商户服务器可能无法及时收到微信支付的结果通知。为了确保订单状态的准确性,商户服务器可以调用微信支付的查询订单 API(https://api.mch.weixin.qq.com/pay/orderquery)主动查询订单的支付结果。
    • 查询订单接口的请求参数主要包括:
      • appid:小程序的 AppID。
      • mch_id:微信支付商户号。
      • nonce_str:随机字符串。
      • out_trade_no:商户系统内部的订单号。
      • sign:签名,根据请求参数和商户密钥按照微信支付签名规则生成。
    • 示例代码(以 Python 为例):

 

import requests

import xml.etree.ElementTree as ET

import hashlib

import hmac

import random

import string

appid = ‘your – appid’

 

牛码网声明:
1、本站所有资源全部收集于互联网,分享目的仅供大家学习与参考,商用请购买正版,如有侵权,请联系niumaw@email.cn及时删除!
2、本站资源不保证其完整性和安全性,下载后请自行检测安全,在使用过程中出现的任何问题均与本站无关,请自行处理!
3、本站为分享资源社区,所有资源问题,本站没责任,更没义务提供任何性质的技术支持,需要技术支持的请购买官方商业版!
4、访问(牛码网 www.niumaw.cn)的用户必须明白,(牛码网 www.niumaw.cn)对提供下载的软件及其它资源不拥有任何权利,其版权归该下载资源的合法拥有者所有!
5、未经(牛码网 www.niumaw.cn)的明确许可,任何人不得盗链本站下载资源;不得复制或仿造本网站或者在非(牛码网 www.niumaw.cn)所属的服务器上建立镜像,(牛码网 www.niumaw.cn)对其自行开发的或和他人共同开发的所有内容、技术手段和服务拥有全部知识产权,任何人不得侵害或破坏,也不得擅自使用。
6、请您认真阅读上述内容,购买即意味着您同意上述内容。

相关资源