一次痛苦又甜蜜的微信支付踩坑之旅

凡是和钱打交道的事,没有一样是容易的。这是我第一次接触微信支付,发现网上还是有很多同学在求助,XXX了怎么办?XXX是什么情况?为了帮助更多的小伙伴脱离“苦海”,我决定写下这次的踩坑之旅,给更多的人帮助。

介绍

微信支付方式分为刷卡支付、公众号支付、扫码支付、APP支付、H5支付、小程序支付。

先从应用场景来各自说一说,这样,能够最快的判断出应该选择哪一种支付。

刷卡支付:使用扫描设备(扫描枪)多见于超市、便利店使用 公众号支付:嵌入公众号的H5页面 扫码支付:用户打开“微信扫一扫”,扫描商户的二维码并支付 APP支付:外部APP应用,用户触发支付时,转到微信内完成支付 H5支付:非微信内置浏览器请求微信支付 小程序支付:用户在微信小程序中使用微信支付背景

我们公司申请的是微信服务号,需要微信支付的是嵌入服务号内部的网页,所以根据介绍,应该选择“公众号支付”。

开发步骤

首先不要被微信支付的开发吓着,其实它很简单。先仔细看公众号支付的文档,看不懂的多看几遍,还看不懂的,动手操作一下,试一试。

文档在此:
pay.weixin.qq.com/wiki/doc/ap…

步骤一:统一下单

跟着文档,咱一点点来,搞明白每一步是为什么,就不会迷迷糊糊搞不清楚了。

首先说一下,这个接口是后台需要完成的,这个接口的目的就是获取prepay_id,它是预支付交易回话标识。将prepay_id传给前台,前台调用js-sdk,这属于步骤二的范围了,一会讲。

接口链接

URL地址:api.mch.weixin.qq.com/pay/unified…

在文档中说明了,必须使用post 方法请求微信给的接口链接,传入的数据也必须是xml格式,返回的也是xml的。醉了?不要醉,微信是这样的,支付宝也是这样的。手动微笑,接受吧。

接着来。

简单粗暴贴代码:

  1. // ‘/addOrder‘是留给前台的调用接口
  2. router.post(‘/addOrder‘,(req,res)=>{
  3. const addOrderUrl = ‘https://api.mch.weixin.qq.com/pay/unifiedorder‘;
  4. var client_ip = "";
  5. client_ip = req.body.ipaddr;
  6. var appid = "1234567890"; // 服务号|公众号的appid
  7. var body = "商品简单描述-测试"; // 商品简单描述
  8. var mch_id= "1234567890"; // 商户号,申请微信支付,腾讯给的商户号
  9. // var device_info = "WEB";
  10. var nonce_str = getRanId(32); // 随机字符串
  11. var out_trade_no = "" +new Date().getTime() + Math.floor( Math.random() * 10 ); //商户订单号
  12. var total_fee = req.body.total_fee; //支付金额,单位:分
  13. var sign = "";
  14. var notify_url = "http://123.456.789"; //异步接收微信支付结果通知的回调地址
  15. var trade_type = "JSAPI"; // 交易类型
  16. var openid = req.session.openId;
  17. console.log(openid);
  18. var stringA = `appid=${appid}&body=${body}&mch_id=${mch_id}&nonce_str=${nonce_str}&notify_url=${notify_url}&openid=${openid}&out_trade_no=${out_trade_no}&spbill_create_ip=${client_ip}&total_fee=${total_fee}&trade_type=${trade_type}`;
  19. var stringSighTemp = stringA+"&key=****#####jiaoyuguihuayuan----***"; //32位的商户key,自定义的,这里为了隐私,我用的特殊符号给你们展示
  20. sign = md5(stringSighTemp).toUpperCase();
  21. var xml = `<xml>
  22. <appid>${appid}</appid>
  23. <body>${body}</body>
  24. <mch_id>${mch_id}</mch_id>
  25. <nonce_str>${nonce_str}</nonce_str>
  26. <notify_url>${notify_url}</notify_url>
  27. <openid>${openid}</openid>
  28. <out_trade_no>${out_trade_no}</out_trade_no>
  29. <spbill_create_ip>${client_ip}</spbill_create_ip>
  30. <total_fee>${total_fee}</total_fee>
  31. <trade_type>${trade_type}</trade_type>
  32. <sign>${sign}</sign>
  33. </xml>`;
  34. var Res = res;axios({
  35. method: ‘post‘,
  36. url: addOrderUrl,
  37. data: xml,
  38. responseType: ‘text/xml‘,
  39. headers: {
  40. ‘Content-Type‘: ‘text/xml‘
  41. }
  42. }).then( res=>{
  43. console.log(res)
  44. Res.send(res.data)
  45. }).catch( err=>{
  46. console.log( err)})
  47. })

复制代码

说明

client_ip 参数 是客户端的ip地址,本来我是在后台获取客户端ip地址的,因为我们使用了nginx代理,req.ip 返回的都是 ::ffff:127.0.0.1 这是IPV6格式的字符串。网上有一个答案对此做出了解释: stackoverflow.com/questions/2…

在这里,我用的一个网上的脚本在前台获取的, http://pv.sohu.com/cityjson?ie=utf-8
使用方法: window.ipaddr = returnCitySN[‘cip’];
其他的参数,都是参考微信支付的要求去写的。

出现的错误

XML格式错误

而查看文档,原因是这样的

我:#&(%#@+%),也不给个详细点的说明…

这种错误需要“顿悟”,我突然发现了我的错误。是我理解错了!我给body标签加了一个 导致我的xml格式错误,其实是有detail字段才需要添加 <[CDATA[]]>, 其他的不需要。

我:咳咳,低级错误。注意看文档,按照要求来,既不多添什么,也不要少什么。

我把<[CDATA[]]>去掉之后,发现果真是这个原因,不再出现XML格式错误了,然而,还是高兴的太早,因为它报了签名错误。呵呵呵~

签名错误

文档中说的签名计算很严格:

第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特别注意以下重要规则:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

参数名ASCII码从小到大排序(字典序);

如果参数的值为空不参与签名;

参数名区分大小写; (公众号支付全是小写)

验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。

微信接口可能增加字段,验证签名时必须支持增加的扩展字段

第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。

key设置路径:微信商户平台(pay.weixin.qq.com)–>账户设置–>API安全–>密钥设置

这里我查阅了一些资料,看到过有这样几种错误情况:
key 看错了,这里应该写商户的key,而这个key 是用户手动设置的,长32位。注意:自己保存一份,因为设置好了之后是没法打开查看的。

还有一种错误,我觉得很离谱啊,body里面不能有中文,然而,我把body中的文字改为英文,发现并不能改变现状,其实用中文是可以的。

总之,找到的这些错误,通通对我的情况没用!

然后这又需要“顿悟”,原来stringA字符串我用了换行符把很长的字符隔开,这导致换行符被转换为Ascall码中的 \n 写进了签名里面,所以,sign错误,所以要么,把换行符通通去掉,要么用“”连接,舍弃。我把换行都去掉之后,就没有签名错误了。

当当当当 ~

终于完成了第一步,后台成功的返回了我们需要的prepay_id

这里为了安全,对于返回sign,和发送的sign进行对比,完全相等之后,才能把结果返回给前台。

步骤二:调用微信js-sdk接口

微信支付

发起一个微信支付请求

前台收到的是xml数据,要先解析一下,得到prepay_id

然后调用微信支付js-sdk,为了大家少走一些弯路,我先来正确的写法,关键步骤如下:

  1. var {prepay_id,appid} = getInfo(res.data); //从后台数据中获取appid 和 prepay_id
  2. nonceStr = getRanId(32);
  3. timeStamp = new Date().getTime();
  4. var stringA = "appId="+appid+"&nonceStr="+nonceStr+"&package=prepay_id="+prepay_id+"&signType=MD5&timeStamp="+timeStamp;
  5. var stringSignTemp = stringA+"&key=****#####jiaoyuguihuayuan----***";
  6. paySign = md5(stringSignTemp).toUpperCase();
  7. window.wx.chooseWXPay({
  8. timestamp: timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
  9. nonceStr: nonceStr, // 支付签名随机串,不长于 32 位
  10. package: "prepay_id=" + prepay_id, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
  11. signType: ‘MD5‘, // 签名方式,默认为‘SHA1‘,使用新版支付需传入‘MD5‘
  12. paySign: paySign, // 支付签名
  13. success: function (res) {
  14. // 支付成功后的回调函数
  15. console.log(res)
  16. },
  17. fail: function(err){
  18. console.log(err)
  19. }});

复制代码

备注:prepay_id 通过微信支付统一下单接口拿到,paySign 采用统一的微信支付 Sign 签名生成方法,注意这里 appId 也要参与签名,appId 与 config 中传入的 appId 一致,即最后参与签名的参数有appId, timeStamp, nonceStr, package, signType。

注意,我要讲个坑点~

调用js-sdk时,签名中的字段都是小驼峰的写法,timeStamp是这样写的,但是wx.config中,timestamp 是全小写的,所以,亲们,千万不要搞错了,我在这里就被坑了好一会呢。

写完签名之后,当你用微信web开发者工具去测试的话,就会看到,“不支持模拟”这样的提示。这个时候,不要犹豫,直接上真机去测试,这并不是我们的程序出现了问题。

小tips: 在真机上,我们是没有办法看到console出的一些调试信息,所以,要想个办法,可以用alert,也可以把调试信息打印在屏幕上面,我选择打印在屏幕上。这里要说一些,微信给的文档没有那么齐全,有一些是要试试才指导的,比如wx.config中的success和fail函数,参数信息怎么打印,其实是res.errMsg和err.errMsg.

上面我说的这些你都注意到了,但是微信支付的控件你依然调动不起来的话,可能是微信商户平台的开发配置出现了问题,在 产品中心-开发配置-支付配置-公众号支付 中进行配置,配置的时候,注意一定要到最后一级目录,比如我要在cms.123.456/book/list/index.html页面中去进行微信支付,那么你的配置应该是 cms.123.456/book/list/

好了,开发中基本上所有的坑都提到了,这是建立在你配置没有出错的情况下。接下来,看看到底能不能真的支付。

完成

大功告成,让我想起了,最近流行的一句话,你这磨人的小妖精,微信支付!

希望能给你们带来帮助~

原文地址:https://www.cnblogs.com/Goodl-luck/p/8605700.html

时间: 2024-10-07 13:17:31

一次痛苦又甜蜜的微信支付踩坑之旅的相关文章

url带#号,微信支付那些坑

现在前端很多框架的前端路由都带#号,主要为了做到无刷新跳转页面. 在微信公众号做微信支付时,配置的支付路径比如是http://www.eee.com/#/order,在调微信支付的方法时错误信息是'URL未注册'. 我的解决方案是,写一个专门做为微信支付的页面,ajax请求后台返回需要调取微信支付的数据(签名等信息),然后把这些信息暂存起来(可以用h5的缓存,记得支付完清掉,如果用node,可以用node的缓存,以自己的实际项目方便).跳转到支付的页面 <!DOCTYPE html><h

iOS SDK微信支付填坑!(跳转微信支付,只有确定按钮)

这两天接微信支付的SDK,遇到了一个天坑,微信文档里面不写清楚,demo里面也没有,参数少了一个无法支付啊有没有!有没有!有没有! 最后调试成功,得知真相的我眼泪掉下来... 先让我们看看是什么情况: --------------------------------------------------------我是分割线-------------------------------------------------------- 预支付订单那块就不说了,基本上都没问题,服务器会返回一个pre

微信支付的坑 返回值 -1

最近在用android接入微信支付.. 之前的包没问题,发现这段时间突然不行了... 于是调试之. 1.开始用的支付配置参数估计有错误,然后支付失败, 获取token值 ,和 prepayId 都是正常的,等在回调支付的文件时候返回错误码-1,其他的参数 都为null 2.使用正确的 微信 appId ,key 和支付的 key 参数,然后进行打包,运行-- 依然结果 一样,前两项都OK,第三步支付界面启动不了,回调返回错误码-1. 疑惑中 --  疑惑中-- 在考虑 1)是否微信sdk 更新了

微信公众号支付踩坑记

前两周做微信H5支付,在浏览器端用的,天真地以为app挂到公众号中也能用,结果不行>"<|||| ,只好再对接一次公众号支付,微信的支付对接下来总体感觉就是封装地不如支付宝,文档不完善,坑贼多.本文会主要关注对接过程中所遇到的问题,以及部分实现代码. 1.介绍 公众号支付(JSAPI支付)是指用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块来完成支付,适用于在公众号.朋友圈.聊天窗口等微信内完成支付的场景.注意公众号支付必须在微信环境

iOS集成微信支付各种坑收录

统一下单的参数要拼接成XML格式,使用AFN请求时,要对参数转义,直接传入字典给AFN,无法识别(这个接口,微信demo中并没有提供示例) AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; //这里传入的xml字符串只是形似xml,但是不是正确是xml格式,需要使用af方法进行转义 manager.responseSerializer = [[AFHTTPResponseSerial

微信支付的坑(jsapi)

具体流程网上都有,主要说一下前端开发者应该主要的,简单的说就两步. 1,获取所需要的参数信息(和后台开发沟通) getWxPayInf() { PayApi.GetWxPay({ money: Math.abs(+this.payNumber), Title: this.title }) .then(res => { if (res.ErrorCode == 1) { if (typeof WeixinJSBridge == "undefined") { if (document

公众号微信支付

1.概要 公众号是以微信用户的一个联系人形式存在的,支付是微信服务号的核心一环. 本篇主要介绍微信支付这一功能,避免大家再跳微信支付的坑. 1.1 关于Magicodes.WeChat.SDK MAGICODES.WECHAT.SDK为心莱团队封装的轻量级微信SDK,现已全部开源,开源库地址为:https://github.com/xin-lai/Magicodes.WeChat.SDK 更多介绍,请关注后续博客. 2.微信公众号支付 用户已有商城网址,用户通过微信消息.微信扫描二维码.微信自定

微信支付.net官方坑太多,我们来精简

微信支付官方坑太多,我们来精简 我把官方的代码,打包成了 an.wxapi.dll. 里面主要替换了下注释.呵呵.然后修改了几个地方. 修改一.Config.cs 1 namespace an.wxapi 2 { 3 public class WxPayConfig 4 { 5 6 public static string AppKey(string key) 7 { 8 return System.Configuration.ConfigurationManager.AppSettings[k

微信支付官方.net版之坑你没商量

//来源:http://www.cnblogs.com/ancms/p/4571567.html 微信支付官方.net版之坑你没商量 最近开始弄支付这块,先是支付宝手机网站支付,也是坑了我许久,不过还好,问题不大. 让我们看看微信支付有多少坑 微信商户平台,你们知道么(我前天才知道,别笑我) 登录地址:https://mch.weixin.qq.com 我查了很久,才知道,原来,帐号密码,发到你开户的邮箱里了,然后,我翻啊翻,终于让我找到帐号密码了. 实在不明白,帐号为嘛是:[email pro