Node.js 微信公众号 H5 支付全流程开发指南

作者:服务小站时间:2026-10-30 14:12:26浏览:624

本文详细介绍如何在 Node.js 环境下实现微信公众号 H5 支付功能。内容涵盖 OAuth2 授权获取 openid、统一下单接口获取 prepay_id、前端 JSAPI 调起支付以及支付结果异步回调处理。针对 Node.js 框架中 XML 解析的特殊需求,提供了 body-parser-xml 中间件的配置方案,帮助开发者顺利完成支付闭环。

Node.js 微信公众号 H5 支付概述

在 Node.js 环境中开发微信公众号功能,特别是移动端 H5 页面调用微信支付接口,是许多开发者面临的实际需求。目前微信官方尚未提供 Node.js 版本的支付 SDK,因此需要手动实现相关逻辑。本文将详细梳理基于 Node.js 和 H5 页面完成微信支付需求的完整开发流程,旨在帮助开发者顺利解决支付功能集成问题。

获取用户授权 Code

一. 请求 CODE

获取 code 的核心目的是获取用户的 openid(用户在该公众号下的唯一标识)以及 access_token。请求使用的 API 地址为:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect。调用此 API 时需重点关注以下参数配置:

1. appid:公众号的 AppID,可在公众号后台查看。 2. redirect_uri:自定义的微信回调地址。用户授权后,微信会携带 code 跳转至该地址。注意 redirect_uri 需要进行 URL 编码,PHP 环境下使用 urlencode,Node.js 环境下需使用 encodeURLComponent(url) 进行编码。 3. response_type=code:固定参数,具体说明可参考微信官网文档。 4. scope=snsapi_userinfo:固定参数,具体说明可参考微信官网文档。 5. state=STATE:固定参数,具体说明可参考微信官网文档。 6. #wechat_redirect:固定参数,具体说明可参考微信官网文档。 ps:官网链接:

通过 Code 获取 Access Token

二. 通过 code 获取 access_token 和 openid

在第一步获取到 code 后,接下来需通过该 code 获取 access_token 和 openid。请求的 API 地址为:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code。该 API 的参数说明如下:

1. appid:微信公众号 ID,从公众号后台获取。 2. secret:微信公众号密钥,从公众号后台获取。 3. code:第一步中获取到的 code 值。 4. grant_type=authorization_code:固定参数。

三. 通过 access_token 调用接口

获取到 access_token 后,可用于后续功能调用。具体接口使用方法可参考官方示例:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316518&lang=zh_CN

前端调起微信支付接口

四. 网页端调起支付 API

虽然看起来只需在网页端调用微信支付功能即可,但实际还有细节需要注意。在微信浏览器内打开 H5 网页时,需通过 JS 调起支付接口,输入输出数据格式均为 JSON。请注意,WeixinJSBridge 内置对象在其他非微信浏览器中无效。示例代码如下:


function onBridgeReady(){
 WeixinJSBridge.invoke(
 'getBrandWCPayRequest', {
  "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 
  "timeStamp":" 1395712654",  //时间戳,自1970年以来的秒数 
  "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串 
  "package" : "prepay_id=u802345jgfjsdfgsdg888", 
  "signType" : "MD5",  //微信签名方式: 
  "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 
 },
 function(res){ 
  if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 
 }
 ); 
}
if (typeof WeixinJSBridge == "undefined"){
 if( document.addEventListener ){
 document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
 }else if (document.attachEvent){
 document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
 document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
 }
}else{
 onBridgeReady();
}

观察上述代码可知,调用微信支付功能需要传递特定参数,


{
 "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 
 "timeStamp":" 1395712654",  //时间戳,自1970年以来的秒数 
 "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串 
 "package" : "prepay_id=u802345jgfjsdfgsdg888", 
 "signType" : "MD5",  //微信签名方式: 
 "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 
}

参数说明如下:

1. appId:公众号名称,由商户传入。 2. timeStamp:时间戳,自 1970 年以来的秒数。此处需特别注意,时间戳必须为字符串格式,即需用引号包裹。 3. nonceStr:32 位随机串,后续将提供生成方法。 4. signType:微信签名方式,通常为 MD5。 5. paySign:微信签名,后续说明。 6. package:关键参数,其来源将在下文说明。 ps: 官网接口说明:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6

统一下单获取 Prepay ID

五. 获取 package,从微信统一下单接口获取 prepay_id

官方 API 地址为:https://api.mch.weixin.qq.com/pay/unifiedorder

请求参数较多,但部分非必填,以下是必须参数:


{
 appid : APPID,
 attach : ATTACH,
 body : BODY,
 mch_id : MCH_ID,
 nonce_str: NONCE_STR,
 notify_url : NOTIFY_URL,// 微信付款后的回调地址
 openid : OPENID,
 out_trade_no : OUT_TRADE_NO ,//new Date().getTime(), //订单号
 spbill_create_ip : SPBILL_CREATE_IP , //客户端的 ip
 total_fee : TOTAL_FEE, //商品的价格, 此处需要注意的是这个价格是以分算的, 那么一般是元, 你需要转换为 RMB 的元
 trade_type : 'JSAPI',
}

微信统一下单接口要求传递 XML 格式数据,且数据需进行签名。首先需对数据进行签名,签名规则可参考微信官方提供的签名规则(签名方法将在后文给出)。微信官方签名规则链接为:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3

生成签名后,需将数据组装为 XML 格式:


var body = '<xml> ' +
 '<appid>'+config.wxappid+'</appid> ' +
 '<attach>'+obj.attach+'</attach> ' +
 '<body>'+obj.body+'</body> ' +
 '<mch_id>'+config.mch_id+'</mch_id> ' +
 '<nonce_str>'+obj.nonce_str+'</nonce_str> ' +
 '<notify_url>'+obj.notify_url+'</notify_url>' +
 '<openid>'+obj.openid+'</openid> ' +
 '<out_trade_no>'+obj.out_trade_no+'</out_trade_no>'+
 '<spbill_create_ip>'+obj.spbill_create_ip+'</spbill_create_ip> ' +
 '<total_fee>'+obj.total_fee+'</total_fee> ' +
 '<trade_type>'+obj.trade_type+'</trade_type> ' +
 '<sign>'+obj.sign+'</sign> ' + // 此处必带签名, 否者微信在验证数据的时候是不通过的
 '</xml>';

接下来请求 API 以获取 prepay_id 值。将上述生成的 XML 数据发送至以下 API 发送给微信,微信验证数据无误后将返回所需值。API 地址:https://api.mch.weixin.qq.com/pay/unifiedorder

六. 获取到 prepay_id 是否即可在 H5 端直接调用微信支付?答案是否定的。

获取到 prepay_id 后,H5 端调起微信支付所需的参数结构如下:


{
 "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 
 "timeStamp":" 1395712654",  //时间戳,自1970年以来的秒数 
 "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串 
 "package" : "prepay_id=u802345jgfjsdfgsdg888", 
 "signType" : "MD5",  //微信签名方式:
}

拥有此类参数后,还需对所有参与签名的参数进行签名。签名规则与上文一致。生成签名后,需将签名结果 paySign 赋值给 H5 调起支付参数的对应字段(注意:微信签名不参与此次签名生成)。最终参数结构如下:


{
 "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 
 "timeStamp":" 1395712654",  //时间戳,自1970年以来的秒数 
 "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串 
 "package" : "prepay_id=u802345jgfjsdfgsdg888", 
 "signType" : "MD5",  //微信签名方式:
 "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名
}

若各环节无误,得到上述参数后即可正常调起微信支付功能,其体验与原生应用无异(无需 App 即可使用 App 级支付功能,确实神奇)。

支付结果异步回调处理

七. 支付完成的回调

微信支付完成后,H5 页面的支付回调函数会返回结果。若 res.err_msg 等于 "get_brand_wcpay_request:ok",则表示前端支付成功。但这并不意味着流程结束,因为还需确认微信是否实际收到款项以及金额是否与传递值一致。此外,还需将支付结果写入数据库等处理。在统一下单接口中有一个必须参数 notify_url(微信付款后的回调地址),该地址由商户提供。用户付款后,微信会以 POST 方式请求此接口,并传递用户付款信息,数据格式为 XML。XML 格式大致如下:


<xml>
 <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
 <attach><![CDATA[支付测试]]></attach>
 <bank_type><![CDATA[CFT]]></bank_type>
 <fee_type><![CDATA[CNY]]></fee_type>
 <is_subscribe><![CDATA[Y]]></is_subscribe>
 <mch_id><![CDATA[10000100]]></mch_id>
 <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str>
 <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid>
 <out_trade_no><![CDATA[1409811653]]></out_trade_no>
 <result_code><![CDATA[SUCCESS]]></result_code>
 <return_code><![CDATA[SUCCESS]]></return_code>
 <sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign>
 <sub_mch_id><![CDATA[10000100]]></sub_mch_id>
 <time_end><![CDATA[20140903131540]]></time_end>
 <total_fee>1</total_fee>
 <trade_type><![CDATA[JSAPI]]></trade_type>
 <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
</xml>

可根据自身业务逻辑解析此 XML 数据。注意:获取数据后需向微信返回回应,若一直不回应,微信会多次重试请求,可能导致逻辑异常。因此,需返回 XML 格式的回应。


<xml>
 <return_code><![CDATA[SUCCESS]]></return_code>
 <return_msg><![CDATA[OK]]></return_msg>
</xml>

小坑提示:在使用 Node.js 和 Express 框架开发时,若在微信支付成功后的回调中无法获取到 XML 值,需安装组件 body-parser-xml。可通过 npm install body-parser-xml --save 安装,并在 app.js 中使用 require('body-parser-xml')(bodyParser); 以中间件方式使用。


// 解决微信支付通知回调数据
app.use(bodyParser.xml({
 limit: '2MB', // Reject payload bigger than 1 MB
 xmlParseOptions: {
 normalize: true, // Trim whitespace inside text nodes
 normalizeTags: true, // Transform tags to lowercase
 explicitArray: false // Only put nodes in array if >1
 }
}));

配置后,即可正常获取微信的 XML 数据。

使用方法如下:


pay.getAccessToken({
 notify_url : 'http://demo.com/', //微信支付完成后的回调
 out_trade_no : new Date().getTime(), //订单号
 attach : '名称',
 body : '购买信息',
 total_fee : '1', // 此处的额度为分
 spbill_create_ip : req.connection.remoteAddress,
 }, function (error, responseData) {
 res.render('payment', {
  title : '微信支付',
  wxPayParams : JSON.stringify(responseData),
  //userInfo : userInfo
 });
 });

至此,内容基本完整。如有不当之处,敬请指正。

附上我的代码仓库:https://git.oschina.net/anziguoer/wechatPay

本文已被整理至《JavaScript 微信开发技巧汇总》,欢迎学习阅读。

为大家推荐当前关注度较高的微信小程序教程:《微信小程序开发教程》,由小编精心整理,希望读者喜欢。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章