一.某行微信公众号支付的“上下文”:
商户关注“某行微信公众号”,并绑定商户信息完成签约。消费者进行支付操作。支付成功后,行方通过微信公众号将交易结果推送给该商户。如商户收到推送通知,则视为交易完成。
二.微信公众号支付开发文档解释
1.一般性流程解释
援引微信公众号支付开发文档,场景介绍部分,链接及截图如下(FSCapture网页滚动截图),注:官方文档这部分内容很粗略,当做科普性文章看….,下图文档最后的3条注意是精华:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
新标签打开下图查看标注:
2.[重要]前置配置
主要有网页授权域名配置及授权目录配置两处。
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3
三.本次项目整体流程及API调用细节
跟微信支付系统交互3次:
1.请求授权获取openId,
2.调用统一下单接口获取prepay_id,
3.唤起支付
总体流程为:商户生成二维码——用户扫码——后台发起授权请求——后台收到微信返回的openid——页面跳转至金额输入页——用户输入金额并确认支付——后台异步订单入库,并调用微信统一下单接口预下单,获得prepay_id——页面唤起微信支付浮层,提示用户输入微信交易密码——支付完成,页面根据JS API返回值开始进行跳转——向用户展示支付结果。
注:需要根据自身情况调整时序
时序如图(自画,有侧重,有缺失):
2.各个环节所遇问题及解决办法:(血泪精华)
A. 二维码生成环节:二维码生成规则为商户后台入口url拼接上商户加密编号。
B. 扫码环节:测试环境微信支付宝各自有自己的二维码,生产环境为一码多扫。
C. [重要]授权环节:
参见微信公众平台授权文档。
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
首先,确定需求是否是静默授权,以设定响应scope。
其次,授权请求相关参数必须用get方式提交,由于锚点(#wechat_redirect)的存在,只能手拼…
最后,redirect_url不要编码!不要编码!不要编码!
D. 调用统一下单接口预下单环节:
报文可用XStream封装,也可用Demo中的成例(微信方面对此不提供技术支持)
测试环境appid送成sub_appid, openid送成sub_openid, sub_mch_id**送商户识别码;**
spbill_create_ip: 用户端ip,request.getRemoteAddr()
E. 支付数据封装环节:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
时间戳timeStamp:可用””+System.currentTimeMillis()/1000 生成;
随机字符串nonceStr:可用UUID.randomUUID().toString.replace(“-”,””) 生成
(我曾用此方法生成10万条数据,长度均为32,不多不少,故无需subString(0,32))
订单详情扩展字符串package: 最XX字段,不仅字段名称是关键字,而且值格式特殊,必须为:”prepay_id=”+prepay_id;
支付参数签名paySign:可用Demo中WXPayUtil中的generateSignature()方法生成,(此方法为整个Demo中最实用方法!),方法需要API密钥,关于密钥设置,参见:
https://docs.youhaosuda.com/topic/s/54f580450abc3e4481000063
F. 唤起支付环节:
两个问题:
1.在请求JSAPI时,如提示“当前页面的url未注册”,检查支付授权目录
2.签名错误,去
https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=20_1校验二者是否一致
使用微信客户端内置对象唤起支付,代码官方给出,写法固定,但是官方代码有小问题,以下代码应置于方法中:
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();
}
样例代码为:
预下单成功后,调用方法wxPayment(obj) 注:obj为后台封装好传递来的支付实体
function wxPayment(obj){
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(obj);
}
}
function onBridgeReady(obj){
var appId = obj.appId; //以appId为例……
WeixinJSBridge.invoke(
‘getBrandWCPayRequest’, {
“appId”:appId ,
“timeStamp”:”1395712654”,
“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,但并不保证它绝对可靠。
上句标红不是因为重要,而是因为这句话实在扯淡…
返回Ok时,location.href=” ”当做支付成功直接跳转到成功逻辑就*好,至于是不是真正成功,可以后台调用订单查询接口进行查询确认,*真失败了可以发起退款…
}
}
);
}
G. 微信支付无沙箱环境,金额实扣!!!
H. 文档并不详实,有的地方太笼统,有的地方太琐碎,仅做参考。
更多FAQ参见:http://kf.qq.com/faq/140225MveaUz150413VNj6nm.html