JSAPI微信支付开发流程和坑
首先,我先简要说明一下微信支付开发的流程
众所周知,工欲善其事,必先利其器,微信官方推出了web微信开发工具,有windows、linux、版本的,根据自己的开发环境选择合适自己的,登陆公众平台-->开发-->开发工具。
根据官网的文档说明,先在微信公众平台里点击微信支付,填写测试授权或支付授权目录,支付测试状态下,设置测试目录,测试人的微信号添加到白名单,发起支付的页面目录必须与设置的精确匹配,而且该域名必须是通过备案的,自己可以写个简单的servlet验证token,如果验证通过,说明该域名是有效的,如果没有验证通过,则说明该域名肯定有问题(排除servlet写的有问题)这一步是可选的,不是必须的,反正,我是当时测过的。
接着,添加测试白名单,填写支付申请。
最后,记得在开发-->接口权限-->网页服务-->网页账号,修改网页授权回调页面域名,授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com无法进行OAuth2.0鉴权
好了,到这里,微信支付的配置信息暂且告一段落,下面开始微信支付开发流程
1)先进行微信网页授权,获取code,引导关注者打开如下页面:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect若提示“该链接无法访问”,请检查参数是否填写错误。
参数说明:
部分代码:
<pre name="code" class="java"><pre name="code" class="java">@SuppressWarnings("deprecation")public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//共账号及商户相关参数String appid = "";//String backUri = "";String backUri = "";//授权后要跳转的链接所需的参数一般有会员号,金额,订单号之类,//最好自己带上一个加密字符串将金额加上一个自定义的key用MD5签名或者自己写的签名,//比如 Sign = %3D%2F%CS% String totals = request.getParameter("totals");String orderNo=request.getParameter("orderNO");//String orderNo=appid+Sha1Util.getTimeStamp();backUri = backUri+"?orderNo="+orderNo+"&describe=test&money="+totals;//URLEncoder.encode 后可以在backUri 的url里面获取传递的所有参数backUri = URLEncoder.encode(backUri);//scope 参数视各自需求而定,这里用scope=snsapi_base 不弹出授权页面直接授权目的只获取统一支付接口的openidString url = "http://open.weixin.qq.com/connect/oauth2/authorize?" +"appid=" + appid+"&redirect_uri=" +backUri+"&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect";response.setCharacterEncoding("UTF-8"); response.sendRedirect(url);}
如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE 。若用户禁止授权,则重定向后不会带上 code 参数,仅会带上 state 参数 redirect_uri?state=STATE
2)通过code换取openid
获取code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
正确时返回的JSON数据包如下:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
错误时微信会返回JSON数据包如下(示例为Code无效错误):
{"errcode":40029,"errmsg":"invalid code"}在这里我遇到了第一坑,openid拿不到,究其原因是网页授权的域名写错了。
3)调用支付接口https://api.mch.weixin.qq.com/pay/unifiedorder
在这里我遇到了第二坑,prepay_id为空,最后查出来是因为商户密钥配错了
请求参数如下:
字段名 |
变量名 |
必填 |
类型 |
示例值 |
描述 |
公众账号ID |
appid |
是 |
String(32) |
wxd678efh567hg6787 |
微信分配的公众账号ID(企业号corpid即为此appId) |
商户号 |
mch_id |
是 |
String(32) |
1230000109 |
微信支付分配的商户号 |
设备号 |
device_info |
否 |
String(32) |
013467007045764 |
终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB" |
随机字符串 |
nonce_str |
是 |
String(32) |
5K8264ILTKCH16CQ2502SI8ZNMTM67VS |
随机字符串,不长于32位。推荐随机数生成算法 |
签名 |
sign |
是 |
String(32) |
C380BEC2BFD727A4B6845133519F3AD6 |
签名,详见签名生成算法 |
商品描述 |
body |
是 |
String(128) |
Ipad mini 16G 白色 |
商品或支付单简要描述 |
商品详情 |
detail |
否 |
String(8192) |
Ipad mini 16G 白色 |
商品名称明细列表 |
附加数据 |
attach |
否 |
String(127) |
深圳分店 |
附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 |
商户订单号 |
out_trade_no |
是 |
String(32) |
20150806125346 |
商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号 |
货币类型 |
fee_type |
否 |
String(16) |
CNY |
符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 |
总金额 |
total_fee |
是 |
Int |
888 |
订单总金额,单位为分,详见支付金额 |
终端IP |
spbill_create_ip |
是 |
String(16) |
123.12.12.123 |
APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。 |
交易起始时间 |
time_start |
否 |
String(14) |
20091225091010 |
订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则 |
交易结束时间 |
time_expire |
否 |
String(14) |
20091227091010 |
订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则 注意:最短失效时间间隔必须大于5分钟 |
商品标记 |
goods_tag |
否 |
String(32) |
WXG |
商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠 |
通知地址 |
notify_url |
是 |
String(256) |
http://www.weixin.qq.com/wxpay/pay.php |
接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。 |
交易类型 |
trade_type |
是 |
String(16) |
JSAPI |
取值如下:JSAPI,NATIVE,APP,详细说明见参数规定 |
商品ID |
product_id |
否 |
String(32) |
12235413214070356458058 |
trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。 |
指定支付方式 |
limit_pay |
否 |
String(32) |
no_credit |
no_credit--指定不能使用信用卡支付 |
用户标识 |
openid |
否 |
String(128) |
oUpF8uMuAJO_M2pxb1Q9zNjWeS6o |
trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。openid如何获取,可参考【获取openid】。企业号请使用【企业号OAuth2.0接口】获取企业号内成员userid,再调用【企业号userid转openid接口】进行转换 |
部分代码:
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//网页授权后获取传递的参数//String userId = request.getParameter("userId"); String orderNo = request.getParameter("orderNo"); String money = request.getParameter("money");String code = request.getParameter("code");//金额转化为分为单位float sessionmoney = Float.parseFloat(money);int paymoney=(int) (sessionmoney*100);String finalmoney=String.valueOf((paymoney));//商户相关资料 String appid = "";String appsecret = "";String partner = "";// 商户号String partnerkey = "";//商户号密钥String openId ="";String URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appid+"&secret="+appsecret+"&code="+code+"&grant_type=authorization_code";JSONObject jsonObject = CommonUtil.httpsRequest(URL, "GET", null);if (null != jsonObject) {openId = jsonObject.getString("openid");System.out.println(openId);PrintWriter pw = response.getWriter(); //pw.print("openId----------->"+openId);}//获取openId后调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorderString currTime = TenpayUtil.getCurrTime();//8位日期String strTime = currTime.substring(8, currTime.length());//四位随机数String strRandom = TenpayUtil.buildRandom(4) + "";//10位序列号,可以自行调整。String strReq = strTime + strRandom;//商户号String mch_id = partner;//子商户号 非必输//String sub_mch_id="";//设备号 非必输//String device_info="";//随机数 String nonce_str = strReq;//商品描述//String body = describe;//商品描述根据情况修改String body = orderNo;//附加数据//String attach = userId;//商户订单号String out_trade_no = orderNo;int intMoney = Integer.parseInt(finalmoney);//总金额以分为单位,不带小数点int total_fee = intMoney;//订单生成的机器 IPString spbill_create_ip = request.getRemoteAddr();//订 单 生 成 时 间 非必输
// String time_start ="";//订单失效时间 非必输
// String time_expire = "";//商品标记 非必输
// String goods_tag = "";//这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等。String notify_url ="";String trade_type = "JSAPI";String openid = openId;//非必输
// String product_id = "";SortedMap<String, String> packageParams = new TreeMap<String, String>();packageParams.put("appid", appid); packageParams.put("mch_id", mch_id); packageParams.put("nonce_str", nonce_str); packageParams.put("body", body); //packageParams.put("attach", attach); packageParams.put("out_trade_no", out_trade_no); //这里写的金额为1 分到时修改//packageParams.put("total_fee", "1"); packageParams.put("total_fee", finalmoney); packageParams.put("spbill_create_ip", spbill_create_ip); packageParams.put("notify_url", notify_url); packageParams.put("trade_type", trade_type); packageParams.put("openid", openid); RequestHandler reqHandler = new RequestHandler(request, response);reqHandler.init(appid, appsecret, partnerkey);String sign = reqHandler.createSign(packageParams);String xml="<xml>"+"<appid>"+appid+"</appid>"+"<mch_id>"+mch_id+"</mch_id>"+"<nonce_str>"+nonce_str+"</nonce_str>"+"<sign>"+sign+"</sign>"+"<body><![CDATA["+body+"]]></body>"+//"<attach>"+attach+"</attach>"+"<out_trade_no>"+out_trade_no+"</out_trade_no>"+//金额,这里写的1 分到时修改//"<total_fee>"+1+"</total_fee>"+"<total_fee>"+finalmoney+"</total_fee>"+"<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+"<notify_url>"+notify_url+"</notify_url>"+"<trade_type>"+trade_type+"</trade_type>"+"<openid>"+openid+"</openid>"+"</xml>";System.out.println(xml);String allParameters = "";try {allParameters = reqHandler.genPackage(packageParams);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";String prepay_id="";try {prepay_id = new GetWxOrderno().getPayNo(createOrderURL, xml);PrintWriter pw = response.getWriter(); if(prepay_id.equals("")){request.setAttribute("ErrorMsg", "统一支付接口获取预支付订单出错");String json="{\"status\":\"error\",\"message\":\"prepay_id is null\"}";pw.print(json);//response.sendRedirect("error.jsp");return;}} catch (Exception e1) {// TODO Auto-generated catch blocke1.printStackTrace();}SortedMap<String, String> finalpackage = new TreeMap<String, String>();String appid2 = appid;String timestamp = Sha1Util.getTimeStamp();String nonceStr2 = nonce_str;String prepay_id2 = "prepay_id="+prepay_id;String packages = prepay_id2;finalpackage.put("appId", appid2); finalpackage.put("timeStamp", timestamp); finalpackage.put("nonceStr", nonceStr2); finalpackage.put("package", packages); finalpackage.put("signType", "MD5");String finalsign = reqHandler.createSign(finalpackage);//System.out.println("pay.jsp?appid="+appid2+"&timeStamp="+timestamp+"&nonceStr="+nonceStr2+"&package="+packages+"&sign="+finalsign);response.sendRedirect("pay.jsp?appid="+appid2+"&timeStamp="+timestamp+"&nonceStr="+nonceStr2+"&package="+packages+"&sign="+finalsign+"&orderNO="+orderNo);return; }
4)前台页面掉微信支付 js 接口
示例代码如下:
unction onBridgeReady(){WeixinJSBridge.invoke('getBrandWCPayRequest', {"appId" : "", //公众号名称,由商户传入 "timeStamp":" ", //时间戳,自1970年以来的秒数 "nonceStr" : "", //随机串 "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();
}
5)处理回调逻辑
3)步棸自己配置notify_url即为支付过后的回调地址,可以为action,静态页面等,自己可以在改回调地址里处理支付过后的业务逻辑
到这里,微信jsAPI开发流程已基本全部讲完,最后,在测试的过程中,微信支付是不允许一个订单经常改价钱的,微信支付默认以第一次提交订单的价钱为基准,以后再提交该订单如果价钱不是第一次的价钱,微信支付默认通不过(切记!我这个坑查了我一天),最后,祝大家开发顺利
JSAPI微信支付开发流程和坑相关推荐
- 小程序微信支付开发流程记录
我所在公司需要开发一款商城小程序,里面需要用到微信支付,我负责里面的下单功能,从小程序端到后台的支付流程都是我自己开发的,由于我们组没有人有开发微信支付的经验,只有我有开发过JSAPI的微信支付的经验 ...
- 微信支付开发流程_清晰_易懂_有源码
转自 https://blog.csdn.net/weixin_41497737/article/details/80547243 最近因为公司需求开始开始做微信支付的开发,在网上参考来了很多文章,大 ...
- iOS之“微信支付”开发流程
实现微信支付的开发,iOS端里面只需要四个步骤: 向服务端请求预支付,获得prepayid以及noncestr: 把参数拼起来签名: 发起支付请求: 处理支付结果. iOS的微信SDK的接入:即为&q ...
- android支付宝、微信支付开发流程
这一段时间项目需要加上微信支付和支付宝支付,经过一段时间摸索,总算能够正常进行支付使用了.想想在支付上遇到的坑,我觉得有必要进行一个记录,在后续的开发中避开支付中遇到的坑: 一.支付宝支付: ps:支 ...
- PHP版本微信支付开发----电脑网站扫码支付(native)(心得、总结)
早就听说微信支付比支付宝支付的坑多,但还得得该填的填,该绕的绕, 最终我们网站的微信支付功能成功上线啦♪(^ ∇ ^*) 首先自报家门,我的PHP版本是7,微信demo用的是php_sdk_v3.0. ...
- 微信支付开发(只针对公众号里的h5支付JSAPI)
微信支付后台: https://pay.weixin.qq.com 只有这里设置了,程序中才能使用这个key /*** 微信支付统一下单接口** @param userOrder 订单信息* @ret ...
- 微信支付开发准备工作和详细步骤
微信支付前的准备工作 1 开发者资质认证 微信支付开发第一步就是使用公司管理者/高层帐号登录微信开放平台,进入"账号中心",进行开发者资质认证,需要填写公司资料,包括但不限于,公司 ...
- 微信公众平台微信支付打通流程
//针对v3版本,jsapi支付,php 1.收到邮件后先去设置api密钥,下载api证书,多次需要手机验证码 2.到公众平台找到开发者中心-接口中找到'网页授权获取用户基本信息',点击修改,加入支付 ...
- 工作笔记——微信支付开发相关知识整理
在最近的工作中,引入了微信小程序支付,在开发过程中积累和整理了一些技术知识,现将其整理如下 目录 一.概念认识 (一)术语介绍 (二)名词解释 (四)对接微信支付接口规则整理 二.微信支付开发参考 ( ...
最新文章
- linux ubuntu kubuntu与xubuntu等各版本差别
- c语言程序的多文件组织,C代码多文件的组织
- Linxu嵌入式汇编语言
- 手机端适应_不轻易透露的超强技巧!详解iVX中怎样做设备自适应
- Bootstrap导航栏
- 作者:李姣(1981-),女,博士,中国医学科学院医学信息研究所副研究员、硕士生导师。...
- 50行代码的MVVM,感受闭包的艺术
- 国内比较好的几大酷站收藏网分享
- redis LRU淘汰策略原理
- 计算机专业学ROSTCM,ROST-CM软件分词和词频统计用法体验
- 威纶通触摸屏上传错误_轻松学会威纶通触摸屏上传与反编译
- 超好用的数据迁移工具
- javascript 动态画心加文字
- C++17之std::apply与std::make_from_tuple
- 熊猫在线压缩图_回归图与熊猫和脾气暴躁
- 01_Snaker简介
- powerbi python词云图_用Power BI制作词云
- Unity 常见英文单词
- LibVLC —— 本地音视频例子、Qt播放例子
- KSO-.NETCore中实现跨域的代码以及几种跨域方式