Mongoose House Technical Edition

如何接入微信服务商支付平台

微信开发者的相关平台包括,

需要注意的是,这些平台的接入方式各不相同,在网上找资料或看帮助文档时,一定要区分是哪个平台的。

服务商平台(Pay平台)有三种支付模式:刷卡支付、公众号支付和扫码支付。以下主要介绍服务商平台公众号支付的接入方法。

开通支付功能

首先,需要开通微信支付服务商功能,文档在此

支付流程

其次,公众号支付有两个步骤,下单支付

下单

下单要调用统一下单接口 https://api.mch.weixin.qq.com/pay/unifiedorder,文档在此

  • 调用方式:POST
  • 编码:UTF-8
  • 参数类型:xml
  • 返回值类型:xml

所有参数在文档上都有说明,下面就一些重点的部分补充如下,

公众账号ID(appid)

服务商公众号开发者ID。这个编号位于MP平台的开发者页面。

公众账号ID

商户号(mch_id)

服务商商户号。这个编号位于Pay平台的商户信息页面。

商户号

子商户号(sub_mch_id)

服务商下管理的特约商户商户号。这个编号可以在Pay平台的特约商户管理页面看到。

子商户号

子商户公众账号ID(sub_appid)

服务商下管理的特约商户如果拥有公众号,这是特约商户公众号开发者ID。这个编号位于特约商户公众号MP平台的开发者页面。

随机字符串(nonce_str)

生成随机字符串的JS代码如下。

var createNonceStr = function () {
  return Math.random().toString(36).substr(2, 15);
};

商品描述(body)

格式为「[服务商公众号名称]-[商品名称]」,文档在此

商户订单号(out_trade_no)

要求商户订单号保持唯一性。重新发起一笔支付要使用原订单号,避免重复支付;已支付过或已调用关单、撤销的订单号不能重新发起支付。

总金额(total_fee)

整数,单位是「分」。例如,“192” 代表 “1元9角2分”。

终端IP(spbill_create_ip)

服务商的后台服务器的 IP 地址。用户手机微信的支付网页位于此 IP 地址。

通知地址(notify_url)

支付成功(或失败)后,微信后台会调用此 URL。流程如下。

微信支付流程

交易类型(trade_type)

公众号支付的交易类型固定是 “JSAPI”。

用户标识和用户子标识(openid和sub_openid)

用户标识是微信用户和微信公众号所关联的编号。用户标识和用户子标识有以下约定,

  1. 用户标识和微信用户账号不同。每个用户对应每个公众号有一个用户标识。一个公众号下有多个用户标识,对于不同的公众号,一个用户也可以对应多个用户标识。
  2. 用户标识或用户子标识两个参数二选一,必传。
  3. 服务商下管理的特约商户如果拥有公众号,那么可以传递用户子标识;如果传递用户子标识,那么必传子商户公众账号ID。
  4. 用户标识必需是服务商的公众号下所关联的用户。如果传用户子标识,那么用户子标识必需是特约商户的公众号下所关联的用户。
  5. 这里的用户标识或用户子标识,必须和下一步支付的微信用户是同一个人。

一个微信公众号下的所有用户标识可以通过以下方法得到,测试页面在此

公众号接口调试页面

其中,access_token 的获取方法在此

参数 AppID 就是服务商公众号的开发者ID,参数 AppSecret 就是服务商公众号的应用密钥。

MP平台的接口调用有次数限制,在此

签名(sign)

当所有参数准备完毕,根据签名算法生成序列值。签名算法在此

在此生成签名,在此验证签名是否有效。

签名测试页面

其中的商户Key 在 Pay平台 ⇒ 账户中心 ⇒ API安全 下设置。


全部参数准备好之后,就可以调用统一下单接口,参数的样子,

<xml>
	<appid>wx2421b1c4370ec43b</appid>
	<body>测试账号-商品</body>
	<mch_id>10000100</mch_id>
	<nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
	<notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url>
	<openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
	<out_trade_no>1415659990</out_trade_no>
	<spbill_create_ip>14.23.150.211</spbill_create_ip>
	<sub_mch_id>1010958222</sub_mch_id>
	<total_fee>192</total_fee>
	<trade_type>JSAPI</trade_type>
	<sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>

返回值的样子,

<xml>
	<return_code><![CDATA[SUCCESS]]></return_code>
	<return_msg><![CDATA[OK]]></return_msg>
	<appid><![CDATA[wx2421b1c4370ec43b]]></appid>
	<mch_id><![CDATA[10000100]]></mch_id>
	<sub_mch_id><![CDATA[1010958222]]></sub_mch_id>
	<nonce_str><![CDATA[QRye3nrY8yK9bShx]]></nonce_str>
	<sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
	<result_code><![CDATA[SUCCESS]]></result_code>
	<prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
	<trade_type><![CDATA[JSAPI]]></trade_type>
</xml>

返回值中最重要的就是 prepay_id。在接下来的支付环节中需要用到这个值。

支付

Pay平台服务商支付的文档在此注意! 不要和MP平台公众号的支付搞混了。

编码

支付步骤简单如下,

  1. 微信用户访问服务商的支付界面,选择支付;
  2. 在支付界面上,使用 Javascript,调用微信浏览器内嵌的 WeixinJSBridge对象;
  3. WeixinJSBridge对象调用微信后台的支付功能,联合用户的微信程序完成支付;
  4. 完成支付后,前台 Javascript 会异步返回结果,同时,微信后台会调用订单中设置的 notify url。

点击支付按钮后的代码如下。

<input type="button" onclick="javascript:pay();" value="支付">
function pay() {
   WeixinJSBridge.invoke(
       'getBrandWCPayRequest', {
           "appId": "wx2421b1c4370ec43b",   
           "timeStamp": "1480473564",     
           "nonceStr": "QRye3nrY8yK9bShx",
           "package": "prepay_id=wx201411101639507cbf6ffd8b0779950874",     
           "signType": "MD5",
           "paySign": "7921E432F65EB8ED0CE9755F0E86D72F"
       },
       function(res) {
           if(res.err_msg == "get_brand_wcpay_request:ok" ) {
           		alert('支付完成!');
           }
       }
   ); 
}

上述参数简单解释如下,

  • appId:服务商的公众号的开发者ID
  • timeSamp:自1970年1月1日 0点0分0秒以来的秒数
  • nonceStr:随机字符串
  • prepay_id:订单编号,由第一步下订单后返回
  • signType:固定为“MD5”
  • paySign:签名,签名算法在此,签名校验工具在此

生成签名

取时间戳的 Javascript 代码如下,

var createTimestamp = function () {
  return parseInt(new Date().getTime() / 1000) + '';
};

发布

首先,需要在 Pay平台 ⇒ 服务商功能 ⇒ 特约商户管理 ⇒ 开发配置 ⇒ 支付权限中开通公众号支付,并设置 JS API 授权目录。如果测试,还应设置测试目录和测试白名单。

发布

JS API 授权目录或测试目录,即服务商后台服务器的地址。有几点注意,

  1. 测试目录可以直接写 IP 地址, JS API 授权目录必须是域名,且域名必须在工信部备案(有ICP编号);
  2. 服务器必须是80端口;
  3. 支付界面不能直接位于服务器地址的根下,必须有1~2级子目录。

例如,

  • 服务商的服务器地址:https://www.host.com
  • 测试服务器 IP:10.10.10.10
  • 支付页面地址:https://www.host.com/shop/pay.html
  • 测试页面地址:http://10.10.10.10/test/pay.html

那么,

  • JS API 授权目录:https://www.host.com/shop/
  • 测试目录:http://10.10.10.10/test/

配置好Pay平台后,约10分钟左右生效。

生效后,把支付页面发布到配置的服务器地址,使用手机的微信浏览器访问支付界面,点击支付按钮,微信就会弹出支付请求。

注意! 打开微信浏览器支付的微信用户必须和之前下订单参数中的用户标识是同一个用户。