企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET
原文:企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET

先看效果

1.本文演示的是微信【企业号】的H5页面微信支付

2.本项目基于开源微信框架WeiXinMPSDK开发:https://github.com/JeffreySu/WeiXinMPSDK 感谢作者苏志巍的开源精神

一、准备部分

相关参数:

AppId:公众号的唯一标识(登陆微信企业号后台 - 设置 - 账号信息 - CorpID)

AppSecret:(微信企业号后台 - 设置 - 权限管理 - 新建一个拥有所有应用权限的普通管理组 - Secret)

Key:商户API密钥(登陆微信商户后台 - 账户中心 - API安全 - API密钥)

MchId:商户ID(微信企业号后台 - 服务中心 - 微信支付 - 微信支付 -商户信息 - 商户号)

后台设置:

微信企业号后台 - 服务中心 - 微信支付 - 微信支付 - 开发配置 :

1.测试授权目录,改成线上支付页面的目录(例:http://www.abc.com/wxpay/)

2.测试白名单,加上测试用户的白名单,只有白名单用户可以付款

二、代码

前端:

使用微信支付先引入JSSDK:http://res.wx.qq.com/open/js/jweixin-1.0.0.js

页面打开即初始化:

        $.ajax({type: "GET",url: "/WxPay/GetPayConfig",beforeSend: function () {$("#btnPay").attr({ "disabled": "disabled" });//获取到配置之前,禁止点击付款按钮},success: function (data) {$("#btnPay").removeAttr("disabled");//获取到配置,打开付款按钮wx.config({debug: true, // 开启调试模式,成功失败都会有alert框appId: data.appId, // 必填,公众号的唯一标识timestamp: data.timeStamp, // 必填,生成签名的时间戳nonceStr: data.nonceStr, // 必填,生成签名的随机串signature: data.signature,// 必填,签名jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表});wx.ready(function () {// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。});wx.error(function (res) {// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。});}});

对应的后端代码:

        /// <summary>/// 获取微信支付配置/// </summary>/// <returns></returns>
        [HttpGet]public JsonResult GetPayConfig(){string timeStamp = Senparc.Weixin.MP.TenPayLib.TenPayUtil.GetTimestamp();string nonceStr = Senparc.Weixin.MP.TenPayLib.TenPayUtil.GetNoncestr();string signature = new Senparc.Weixin.MP.TenPayLib.RequestHandler(null).CreateMd5Sign();return Json(new { appId = AppId, timeStamp = timeStamp, nonceStr = nonceStr, signature = signature }, JsonRequestBehavior.AllowGet);}

用户点击支付触发的函数(微信JSSDK的chooseWXPay函数):

        function startWxPay() {$.ajax({type: "POST",url: "/WxPay/GetPaySign",data: { code: code, openid: openid },beforeSend: function () {$("#btnPay").attr({ "disabled": "disabled" });},success: function (res) {$("#btnPay").removeAttr("disabled");if (res.openid != null && res.openid != undefined && res.openid != "") {window.localStorage.setItem("openid", res.openid);}wx.chooseWXPay({timestamp: res.data.timeStamp, // 支付签名时间戳nonceStr: res.data.nonceStr, // 支付签名随机串,不长于32 位package: res.data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)signType: "MD5", // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'paySign: res.data.paysign, // 支付签名success: function (res) {//支付成功},cancel: function (res) {//支付取消}});}});}

对应的服务端代码:

        /// <summary>/// 支付接口/// </summary>/// <param name="code"></param>/// <param name="openid"></param>/// <returns></returns>
        [HttpPost]public JsonResult GetPaySign(string code, string openid){string body = "支付测试";//支付描述string nonce_str = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetNoncestr();string notify_url = "http://" + HttpContext.Request.Url.Host + "/WxPay/PayNotifyUrl";//支付结果回调地址,不能带参数(PayNotifyUrl回调里能接到订单号out_trade_no参数)string out_trade_no = "WxPay_" + DateTime.Now.ToString("yyyyMMddHHmmssfff");//订单号:32个字符内、不得重复string spbill_create_ip = Request.UserHostAddress;//用户端IPint total_fee = 1;//订单金额(单位:分),整数string trade_type = "JSAPI";//JSAPI,NATIVE,APP,WAP#region 获取用户微信OpenIdstring openidExt = string.Empty;if (string.IsNullOrEmpty(openid)){if (!Senparc.Weixin.QY.Containers.AccessTokenContainer.CheckRegistered(AppId)){Senparc.Weixin.QY.Containers.AccessTokenContainer.Register(AppId, AppSecret);}var accountToken = Senparc.Weixin.QY.Containers.AccessTokenContainer.GetToken(AppId, AppSecret);var user = Senparc.Weixin.QY.AdvancedAPIs.OAuth2Api.GetUserId(accountToken, code);var model = Senparc.Weixin.QY.CommonAPIs.CommonApi.ConvertToOpenId(accountToken, user.UserId);openidExt = model.openid;}else{openidExt = openid;}#endregion#region 调用统一支付接口获得prepay_id(预支付交易会话标识)Senparc.Weixin.MP.TenPayLibV3.RequestHandler packageReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);packageReqHandler.SetParameter("appid", AppId);packageReqHandler.SetParameter("body", body);packageReqHandler.SetParameter("mch_id", MchId);packageReqHandler.SetParameter("nonce_str", nonce_str);packageReqHandler.SetParameter("notify_url", notify_url);packageReqHandler.SetParameter("openid", openidExt);packageReqHandler.SetParameter("out_trade_no", out_trade_no);packageReqHandler.SetParameter("spbill_create_ip", spbill_create_ip);packageReqHandler.SetParameter("total_fee", total_fee.ToString());packageReqHandler.SetParameter("trade_type", trade_type);packageReqHandler.SetParameter("sign", packageReqHandler.CreateMd5Sign("key", Key));string data = packageReqHandler.ParseXML();var result = Senparc.Weixin.MP.AdvancedAPIs.TenPayV3.Unifiedorder(data);var res = System.Xml.Linq.XDocument.Parse(result);string prepay_id = res.Element("xml").Element("prepay_id").Value;#endregion#region 支付参数string timeStamp = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetTimestamp();nonce_str = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetNoncestr();Senparc.Weixin.MP.TenPayLibV3.RequestHandler paysignReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);paysignReqHandler.SetParameter("appId", AppId);paysignReqHandler.SetParameter("timeStamp", timeStamp);paysignReqHandler.SetParameter("nonceStr", nonce_str);paysignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepay_id));paysignReqHandler.SetParameter("signType", "MD5");string paysign = paysignReqHandler.CreateMd5Sign("key", Key);paysignReqHandler.SetParameter("paysign", paysign);#endregionreturn Json(new { data = paysignReqHandler.GetAllParameters(), openid = openidExt }, JsonRequestBehavior.AllowGet);}

前端页面全部代码:

<!DOCTYPE html>
<html>
<head><title>企业号微信支付测试</title><meta http-equiv="content-type" content="text/html;charset=utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css"><script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script><script type="text/javascript" src="http://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
</head>
<body><input type="button" onclick="startWxPay()" class="btn btn-primary btn-lg btn-block" value="点击付费(¥:0.01元)" id="btnPay" style="margin-top:80px;" /><script type="text/javascript">var code = GetQueryString("code");var openid = window.localStorage.getItem("openid");$.ajax({type: "GET",url: "/WxPay/GetPayConfig",beforeSend: function () {$("#btnPay").attr({ "disabled": "disabled" });//获取到配置之前,禁止点击付款按钮
            },success: function (data) {$("#btnPay").removeAttr("disabled");//获取到配置,打开付款按钮
                wx.config({debug: true, // 开启调试模式,成功失败都会有alert框
                    appId: data.appId, // 必填,公众号的唯一标识
                    timestamp: data.timeStamp, // 必填,生成签名的时间戳
                    nonceStr: data.nonceStr, // 必填,生成签名的随机串
                    signature: data.signature,// 必填,签名
                    jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表
                });wx.ready(function () {// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
                });wx.error(function (res) {// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
                });}});function startWxPay() {$.ajax({type: "POST",url: "/WxPay/GetPaySign",data: { code: code, openid: openid },beforeSend: function () {$("#btnPay").attr({ "disabled": "disabled" });},success: function (res) {$("#btnPay").removeAttr("disabled");if (res.openid != null && res.openid != undefined && res.openid != "") {window.localStorage.setItem("openid", res.openid);}wx.chooseWXPay({timestamp: res.data.timeStamp, // 支付签名时间戳
                        nonceStr: res.data.nonceStr, // 支付签名随机串,不长于32 位
                        package: res.data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
                        signType: "MD5", // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
                        paySign: res.data.paysign, // 支付签名
                        success: function (res) {//支付成功
                        },cancel: function (res) {//支付取消
                        }});}});}function GetQueryString(name) {var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");var r = window.location.search.substr(1).match(reg);if (r != null) return unescape(r[2]); return null;}</script>
</body>
</html>

View Code

后端控制器全部代码:

using Senparc.Weixin.HttpUtility;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;namespace CNPCCMS.Controllers
{public class WxPayController : Controller{private static string AppId = "改成你的AppId";private static string AppSecret = "改成你的AppSecret";private static string Key = "改成你的Key";private static string MchId = "改成你的MchId";/// <summary>/// 获取微信支付配置/// </summary>/// <returns></returns>
        [HttpGet]public JsonResult GetPayConfig(){string timeStamp = Senparc.Weixin.MP.TenPayLib.TenPayUtil.GetTimestamp();string nonceStr = Senparc.Weixin.MP.TenPayLib.TenPayUtil.GetNoncestr();string signature = new Senparc.Weixin.MP.TenPayLib.RequestHandler(null).CreateMd5Sign();return Json(new { appId = AppId, timeStamp = timeStamp, nonceStr = nonceStr, signature = signature }, JsonRequestBehavior.AllowGet);}/// <summary>/// 支付接口/// </summary>/// <param name="code"></param>/// <param name="openid"></param>/// <returns></returns>
        [HttpPost]public JsonResult GetPaySign(string code, string openid){string body = "支付测试";//支付描述string nonce_str = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetNoncestr();string notify_url = "http://" + HttpContext.Request.Url.Host + "/WxPay/PayNotifyUrl";//支付结果回调地址,不能带参数(PayNotifyUrl回调里能接到订单号out_trade_no参数)string out_trade_no = "WxPay_" + DateTime.Now.ToString("yyyyMMddHHmmssfff");//订单号:32个字符内、不得重复string spbill_create_ip = Request.UserHostAddress;//用户端IPint total_fee = 1;//订单金额(单位:分),整数string trade_type = "JSAPI";//JSAPI,NATIVE,APP,WAP#region 获取用户微信OpenIdstring openidExt = string.Empty;if (string.IsNullOrEmpty(openid)){if (!Senparc.Weixin.QY.Containers.AccessTokenContainer.CheckRegistered(AppId)){Senparc.Weixin.QY.Containers.AccessTokenContainer.Register(AppId, AppSecret);}var accountToken = Senparc.Weixin.QY.Containers.AccessTokenContainer.GetToken(AppId, AppSecret);var user = Senparc.Weixin.QY.AdvancedAPIs.OAuth2Api.GetUserId(accountToken, code);var model = Senparc.Weixin.QY.CommonAPIs.CommonApi.ConvertToOpenId(accountToken, user.UserId);openidExt = model.openid;}else{openidExt = openid;}#endregion#region 调用统一支付接口获得prepay_id(预支付交易会话标识)Senparc.Weixin.MP.TenPayLibV3.RequestHandler packageReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);packageReqHandler.SetParameter("appid", AppId);packageReqHandler.SetParameter("body", body);packageReqHandler.SetParameter("mch_id", MchId);packageReqHandler.SetParameter("nonce_str", nonce_str);packageReqHandler.SetParameter("notify_url", notify_url);packageReqHandler.SetParameter("openid", openidExt);packageReqHandler.SetParameter("out_trade_no", out_trade_no);packageReqHandler.SetParameter("spbill_create_ip", spbill_create_ip);packageReqHandler.SetParameter("total_fee", total_fee.ToString());packageReqHandler.SetParameter("trade_type", trade_type);packageReqHandler.SetParameter("sign", packageReqHandler.CreateMd5Sign("key", Key));string data = packageReqHandler.ParseXML();var result = Senparc.Weixin.MP.AdvancedAPIs.TenPayV3.Unifiedorder(data);var res = System.Xml.Linq.XDocument.Parse(result);string prepay_id = res.Element("xml").Element("prepay_id").Value;#endregion#region 支付参数string timeStamp = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetTimestamp();nonce_str = Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetNoncestr();Senparc.Weixin.MP.TenPayLibV3.RequestHandler paysignReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler(null);paysignReqHandler.SetParameter("appId", AppId);paysignReqHandler.SetParameter("timeStamp", timeStamp);paysignReqHandler.SetParameter("nonceStr", nonce_str);paysignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepay_id));paysignReqHandler.SetParameter("signType", "MD5");string paysign = paysignReqHandler.CreateMd5Sign("key", Key);paysignReqHandler.SetParameter("paysign", paysign);#endregionreturn Json(new { data = paysignReqHandler.GetAllParameters(), openid = openidExt }, JsonRequestBehavior.AllowGet);}/// <summary>/// 支付结果回调地址/// </summary>/// <returns></returns>
        [HttpPost]public ActionResult PayNotifyUrl(){Senparc.Weixin.MP.TenPayLibV3.ResponseHandler payNotifyRepHandler = new Senparc.Weixin.MP.TenPayLibV3.ResponseHandler(null);payNotifyRepHandler.SetKey(Key);string return_code = payNotifyRepHandler.GetParameter("return_code");string return_msg = payNotifyRepHandler.GetParameter("return_msg");string xml = string.Format(@"<xml><return_code><![CDATA[{0}]]></return_code><return_msg><![CDATA[{1}]]></return_msg></xml>", return_code, return_msg);if (return_code.ToUpper() != "SUCCESS"){return Content(xml, "text/xml");}string out_trade_no = payNotifyRepHandler.GetParameter("out_trade_no");//微信服务器可能会多次推送到本接口,这里需要根据out_trade_no去查询订单是否处理,如果处理直接返回:return Content(xml, "text/xml"); 不跑下面代码//验证请求是否从微信发过来(安全)if (payNotifyRepHandler.IsTenpaySign()){}else{}return Content(xml, "text/xml");}}
}

View Code

三、关键点

1.支付页面的链接不管是放到自定义菜单还是嵌到公众号文章内,或是发到微信对话框让用户点击支付,最终的链接是:https://open.weixin.qq.com/connect/oauth2/authorize?appid=这里改成你的appid&redirect_uri=这里是你支付页面的地址&response_type=code&scope=SCOPE&state=1#wechat_redirect

这种约定的链接最终访问的还是redirect_uri这个链接,同时微信回调这个链接还会带上code和state两个参数。code参数是当前用户,state参数自定义,本文未用到。

2.后台GetPaySign方法同时接收code和openid是为了连续支付或者用户取消了支付再次点击支付设计的(每点一次支付就触发一次后台GetPaySign方法),因为code是微信服务器回调带的,只能用一次。所以第一次code传到后台就调接口获得用户openid发回前端缓存起来,再起发起请求code和openid一起传到后端,这个时候code无效了,但是openid可以用

3.微信支付回调接口(notify_url)不能带参数,但是回调接口里能从微信服务器推过来的xml文件里提取出订单号(out_trade_no),可以对其进行操作

4.还是报错请检查参数大小写,微信api里的参数请严格按照官方文档的大小写

爬虫可耻,本文原始链接:http://www.cnblogs.com/oppoic/p/6132533.html

四、附录

H5调起支付API:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6

统一下单:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

微信JSSDK:https://mp.weixin.qq.com/wiki  微信网页开发 - 微信JS-SDK说明文档 - Ctrl+F搜索:chooseWXPay

OAuth验证接口:http://qydev.weixin.qq.com/wiki/index.php?title=OAuth验证接口

userid转换成openid:http://qydev.weixin.qq.com/wiki/index.php?title=Userid与openid互换接口

posted on 2019-02-19 14:31 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/10400893.html

企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET相关推荐

  1. java微信内h5调起支付_java微信支付--------公众号内H5调起支付

    /*** 统一下单接口,获取prepay_id *@paramrequest *@return */@RequestMapping(value= "/unifiedOrder", ...

  2. php公众号客服消息图文,微信公众号开发系列-发送客服消息(示例代码)

    下面是做微信公众号开发用到最多的两个客服消息发送类型,文本信息和图文信息. 1.发送文本消息{ "touser":"OPENID", "msgtype ...

  3. java微信公众号支付开发平台_Java微信公众平台开发之公众号支付(微信内H5调起支付)...

    官方文档 准备工作:已通过微信认证的公众号,必须通过ICP备案域名(否则会报支付失败) 借鉴了很多大神的文章,在此先谢过了 整个支付流程,看懂就很好写了 一.设置支付目录 在微信公众平台设置您的公众号 ...

  4. Java微信支付开发之公众号支付(微信内H5调起支付)

    官方文档 准备工作:已通过微信认证的公众号,必须通过ICP备案域名(否则会报支付失败) 借鉴了很多大神的文章,在此先谢过了 整个支付流程,看懂就很好写了 一.设置支付目录 在微信公众平台设置您的公众号 ...

  5. 微信公众号接入H5支付

    一.概述 1.H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付.主要用于触屏版的手机浏览器请求微信支付的场景.可以方便的 ...

  6. php 公众号内h5支付宝支付宝支付宝支付宝支付,微信浏览器中支付宝wap支付和微信JSAPI公众号支付...

    手机浏览器只有支付宝wap支付,微信浏览器中出现支付宝wap支付和微信JSAPI公众号支付,其中支付宝wap在线支付没有在新窗口打开(兼容大部分手机),Thinkphp3.2公众号支付 下载资源 下载 ...

  7. 小程序 php wecahtpay,PHP 微信公众号,小程序获取支付参数。微信支付

    PHP 微信公众号,小程序获取支付参数.微信支付 发布时间:2018-09-26 11:19, 浏览次数:278 , 标签: PHP 首先下载微信官方demo放入项目中 地址:https://gith ...

  8. 微信jsapi支付获取code_微信JSAPI公众号支付在部分机型上出现appid参数错误的解决办法 - YangJunwei...

    都说微信支付的坑比较多,老杨感觉还行,就是开始周期和调试过程比较费时费力-_-! 今儿在调试一个基于微信JSAPI公众号的支付项目时发现,部分机型(比如iphone7/vivo-x6d)中微信支付获取 ...

  9. 微信jsapi支付获取code_JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI)

    写这篇文章的目的有2个,一是自己的项目刚开发完微信支付功能,趁热回个炉温习一下,二也是帮助像我这样对微信支付不熟悉,反复看了多天文档还是一知半解,原理都没摸清,更不要说实现了.本以为网上的微信开发教程 ...

最新文章

  1. oracle 四分位函数,Oracle分析函数四——函数RANK,DENSE_RANK,FIRST,LAST…
  2. Leetcode 461. Hamming Distance JAVA语言
  3. 世界机场数据(带位置坐标)
  4. AI: DL方法与问题空间探索
  5. C++对象的动态建立
  6. 五 .3D-2D:PnP问题求解 非线性法BA
  7. python基础学习(四)if判断语句
  8. ajax css文件,wordpress 添加JS,css文件,实现AJAX效果
  9. 双指针(下标)的应用
  10. ip变更会影响账号登陆吗_代理IP的匿名度级别会影响自身稳定性吗
  11. 服务器2003系统U盘安装方法,怎么用u盘装2003系统
  12. 逐行分析jQuery源码
  13. JSP程序设计实训(五)——JSP基本语法(一)
  14. matlab飞机飞行模型,使用 MATLAB/Simulink 设计无人机飞行控制系统(二、动力学模型建立)...
  15. 利用CA证书配置安全Web站点
  16. crontab 每天凌晨12点定时器_crontab命令定时备份执行脚本
  17. 聊一聊异构系统间数据一致性
  18. 【留言板】在这聊个天勾搭一下神犇之类的
  19. Num.01- java 之 mybatis 框架
  20. 华米Q3财报超预期,智能穿戴设备接替手机狂奔?

热门文章

  1. 缺陷的JIRA管理文档
  2. 《HTML、CSS、JavaScript 网页制作从入门到精通》——6.6 单元格属性
  3. Creating Lists
  4. oracle查询保留2位小数
  5. 户外生活--西湖林至千军台
  6. C++创建二维数组和矩阵
  7. LinkedList 源码分析
  8. Spring Security-用户密码自定义国密SM2加密
  9. app打开本系统自动登陆设计
  10. vsftpd服务安装与虚拟用户配置