这次给大家带来公众号支付接口的开发,公众号支付接口开发的注意事项有哪些,下面就是实战案例,一起来看一下。

公众号支付就是在微信里面的H5页面唤起微信支付,不用扫码即可付款的功能。做这个功能首先要明确的就是,只有和商户号mch_id匹配的appid才能成功支付。商户号在注册成功的时候就会将相关信息发送到邮箱里面。而唤起支付的一个关键是靠openid拿到统一下单。而openid是和appid一一对应的。也就是说如果你登录使用的appid不是公众号的appid,得到的openid就无法唤起公众号内的支付(会出现appid和商户号不匹配的错误)。曾经就在这个地方绕了个弯,因为微信的开放平台可以创建网站应用,也有一个appid和appsecreat,也可以在微信里面一键登录。

业务流程

下面是微信的官方流程,看似有点复杂,重点就是要拿到统一下单接口返回的json串,其他按照官方demo基本就能正确,下面说一下几个细节。

创建订单

在调用微信公众号支付之前,首先我们自己要把订单创建好。比如一个充值的订单。主要是先确定下金额再进行下一步。public JsonResult CreateRecharegOrder(decimal money)

{ if (money < (decimal)0.01) return Json(new PaymentResult("充值金额非法!")); var user = _workContext.CurrentUser; var order = _paymentService.CreateRechargeOrder(user.Id, money); return Json(new PaymentResult(true) {OrderId = order.OrderNumber});

}

调用统一下单

订单创建成功之后,页面跳转到支付页面,这个时候就是按照官方的流程去拿prepay_id和paySign,微信的demo中提供了一个jsApiPay的对象。但这个对象需要一个page对象初始化。[LoginValid] public ActionResult H5Pay(string orderNumber)

{ var user = _workContext.CurrentUser; var order = _paymentService.GetOrderByOrderNumber(orderNumber); //判断订单是否存在 //订单是否已经支付了

var openid = user.OpenId; var jsApipay = new JsApiPayMvc(this.ControllerContext.HttpContext);

jsApipay.openid = openid;

jsApipay.total_fee = (int)order.Amount * 100;

WxPayData unifiedOrderResult = jsApipay.GetUnifiedOrderResult();

ViewBag.wxJsApiParam = jsApipay.GetJsApiParameters();//获取H5调起JS API参数

ViewBag.unifiedOrder = unifiedOrderResult.ToPrintStr();

ViewBag.OrderNumber = order.OrderNumber; return View();

}

在MVC中我们简单改一下就可以了。也就是把page对象换成httpContext即可。然后里面的方法就可以直接用了。

JsApiPayMvc:using System;using System.Collections.Generic;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using System.Runtime.Serialization;using System.IO;using System.Text;using System.Net;using System.Web.Security;using LitJson;namespace WxPayAPI

{ public class JsApiPayMvc

{ ///

/// 保存页面对象,因为要在类的方法中使用Page的Request对象 ///

public HttpContextBase context { get; set; } ///

/// openid用于调用统一下单接口 ///

public string openid { get; set; } ///

/// access_token用于获取收货地址js函数入口参数 ///

public string access_token { get; set; } ///

/// 商品金额,用于统一下单 ///

public int total_fee { get; set; } ///

/// 统一下单接口返回结果 ///

public WxPayData unifiedOrderResult { get; set; } public JsApiPayMvc(HttpContextBase _context)

{

context = _context;

} /**

*

* 网页授权获取用户基本信息的全部过程

* 详情请参看网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html

* 第一步:利用url跳转获取code

* 第二步:利用code去获取openid和access_token

*

*/

public void GetOpenidAndAccessToken(string code)

{ if (!string.IsNullOrEmpty(code))

{ //获取code码,以获取openid和access_token

Log.Debug(this.GetType().ToString(), "Get code : " + code);

GetOpenidAndAccessTokenFromCode(code);

} else

{ //构造网页授权获取code的URL

string host = context.Request.Url.Host; string path = context.Request.Path; string redirect_uri = HttpUtility.UrlEncode("http://" + host + path);

WxPayData data = new WxPayData();

data.SetValue("appid", WxPayConfig.APPID);

data.SetValue("redirect_uri", redirect_uri);

data.SetValue("response_type", "code");

data.SetValue("scope", "snsapi_base");

data.SetValue("state", "STATE" + "#wechat_redirect"); string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl();

Log.Debug(this.GetType().ToString(), "Will Redirect to URL : " + url); try

{ //触发微信返回code码

context.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常,不用处理这个异常 } catch(System.Threading.ThreadAbortException ex)

{

}

}

} /**

*

* 通过code换取网页授权access_token和openid的返回数据,正确时返回的JSON数据包如下:

* {

* "access_token":"ACCESS_TOKEN",

* "expires_in":7200,

* "refresh_token":"REFRESH_TOKEN",

* "openid":"OPENID",

* "scope":"SCOPE",

* "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"

* }

* 其中access_token可用于获取共享收货地址

* openid是微信支付jsapi支付接口统一下单时必须的参数

* 更详细的说明请参考网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html

* @失败时抛异常WxPayException */

public void GetOpenidAndAccessTokenFromCode(string code)

{ try

{ //构造获取openid及access_token的url

WxPayData data = new WxPayData();

data.SetValue("appid", WxPayConfig.APPID);

data.SetValue("secret", WxPayConfig.APPSECRET);

data.SetValue("code", code);

data.SetValue("grant_type", "authorization_code"); string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + data.ToUrl(); //请求url以获取数据

string result = HttpService.Get(url);

Log.Debug(this.GetType().ToString(), "GetOpenidAndAccessTokenFromCode response : " + result); //保存access_token,用于收货地址获取

JsonData jd = JsonMapper.ToObject(result);

access_token = (string)jd["access_token"]; //获取用户openid

openid = (string)jd["openid"];

Log.Debug(this.GetType().ToString(), "Get openid : " + openid);

Log.Debug(this.GetType().ToString(), "Get access_token : " + access_token);

} catch (Exception ex)

{

Log.Error(this.GetType().ToString(), ex.ToString()); throw new WxPayException(ex.ToString());

}

} /**

* 调用统一下单,获得下单结果

* @return 统一下单结果

* @失败时抛异常WxPayException */

public WxPayData GetUnifiedOrderResult()

{ //统一下单

WxPayData data = new WxPayData();

data.SetValue("body", "test");

data.SetValue("attach", "test");

data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());

data.SetValue("total_fee", total_fee);

data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));

data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));

data.SetValue("goods_tag", "test");

data.SetValue("trade_type", "JSAPI");

data.SetValue("openid", openid);

WxPayData result = WxPayApi.UnifiedOrder(data); if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")

{

Log.Error(this.GetType().ToString(), "UnifiedOrder response error!"); throw new WxPayException("UnifiedOrder response error!");

}

unifiedOrderResult = result; return result;

} /**

*

* 从统一下单成功返回的数据中获取微信浏览器调起jsapi支付所需的参数,

* 微信浏览器调起JSAPI时的输入参数格式如下:

* {

* "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入

* "timeStamp":" 1395712654", //时间戳,自1970年以来的秒数

* "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串

* "package" : "prepay_id=u802345jgfjsdfgsdg888",

* "signType" : "MD5", //微信签名方式:

* "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名

* }

* @return string 微信浏览器调起JSAPI时的输入参数,json格式可以直接做参数用

* 更详细的说明请参考网页端调起支付API:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7

*

*/

public string GetJsApiParameters()

{

Log.Debug(this.GetType().ToString(), "JsApiPay::GetJsApiParam is processing...");

WxPayData jsApiParam = new WxPayData();

jsApiParam.SetValue("appId", unifiedOrderResult.GetValue("appid"));

jsApiParam.SetValue("timeStamp", WxPayApi.GenerateTimeStamp());

jsApiParam.SetValue("nonceStr", WxPayApi.GenerateNonceStr());

jsApiParam.SetValue("package", "prepay_id=" + unifiedOrderResult.GetValue("prepay_id"));

jsApiParam.SetValue("signType", "MD5");

jsApiParam.SetValue("paySign", jsApiParam.MakeSign()); string parameters = jsApiParam.ToJson();

Log.Debug(this.GetType().ToString(), "Get jsApiParam : " + parameters); return parameters;

} /**

*

* 获取收货地址js函数入口参数,详情请参考收货地址共享接口:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_9

* @return string 共享收货地址js函数需要的参数,json格式可以直接做参数使用 */

public string GetEditAddressParameters()

{ string parameter = ""; try

{ string host = context.Request.Url.Host; string path = context.Request.Path; string queryString = context.Request.Url.Query; //这个地方要注意,参与签名的是网页授权获取用户信息时微信后台回传的完整url

string url = "http://" + host + path + queryString; //构造需要用SHA1算法加密的数据

WxPayData signData = new WxPayData();

signData.SetValue("appid",WxPayConfig.APPID);

signData.SetValue("url", url);

signData.SetValue("timestamp",WxPayApi.GenerateTimeStamp());

signData.SetValue("noncestr",WxPayApi.GenerateNonceStr());

signData.SetValue("accesstoken",access_token); string param = signData.ToUrl();

Log.Debug(this.GetType().ToString(), "SHA1 encrypt param : " + param); //SHA1加密

string addrSign = FormsAuthentication.HashPasswordForStoringInConfigFile(param, "SHA1");

Log.Debug(this.GetType().ToString(), "SHA1 encrypt result : " + addrSign); //获取收货地址js函数入口参数

WxPayData afterData = new WxPayData();

afterData.SetValue("appId",WxPayConfig.APPID);

afterData.SetValue("scope","jsapi_address");

afterData.SetValue("signType","sha1");

afterData.SetValue("addrSign",addrSign);

afterData.SetValue("timeStamp",signData.GetValue("timestamp"));

afterData.SetValue("nonceStr",signData.GetValue("noncestr")); //转为json格式

parameter = afterData.ToJson();

Log.Debug(this.GetType().ToString(), "Get EditAddressParam : " + parameter);

} catch (Exception ex)

{

Log.Error(this.GetType().ToString(), ex.ToString()); throw new WxPayException(ex.ToString());

} return parameter;

}

}

}

View Code

这个页面可以在本地调试,可以比较方便的确认参数是否ok。

唤起支付

官方页面的示例如下:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6 但主要的参数(mark部分)是由后台生成的,也就是上一个步骤的ViewBag.wxJsApiParamfunction onBridgeReady(){

WeixinJSBridge.invoke(

'getBrandWCPayRequest', { "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入

"timeStamp":" 1395712654", //时间戳,自1970年以来的秒数

"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,但并不保证它绝对可靠。

}

);

}

所以在MVC中要这样写:@{

ViewBag.Title = "微信支付";

Layout = "~/Views/Shared/_Layout.cshtml";

}

订单详情:@Html.Raw(ViewBag.unifiedOrder)

支付

//调用微信JS api 支付

function jsApiCall() {

WeixinJSBridge.invoke( 'getBrandWCPayRequest', @Html.Raw(ViewBag.wxJsApiParam),//josn串

function (res)

{

WeixinJSBridge.log(res.err_msg); //alert(res.err_code + res.err_desc + res.err_msg);

if (res.err_msg == "get_brand_wcpay_request:ok") { var num = $("#ordernum").val();

$.post("/payment/WeiXinPaySuccess", { ordernumber: num }, function(data) { if (data.IsSuccess === true) {

alert("支付成功");

location.href = document.referrer;

} else {

}

});

}

if (res.err_msg == 'get_brand_wcpay_request:cancel') {

$('.button').removeAttr('submitting');

alert('取消支付');

}

}

);

} function callpay()

{ if (typeof WeixinJSBridge == "undefined")

{

alert("WeixinJSBridge ="); if (document.addEventListener)

{

document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);

} else if (document.attachEvent)

{

document.attachEvent('WeixinJSBridgeReady', jsApiCall);

document.attachEvent('onWeixinJSBridgeReady', jsApiCall);

}

} else

{

jsApiCall();

}

}

必须要用Html.Raw,不然json解析不对,无法支付。这个时候点击页面,会出现微信的加载效果,但别高兴的太早,还是会出错,出现一个“3当前的URL未注册”

原因就在于,需要在公众号中设置支付目录。而这个支付目录是大小写敏感的,所以你得多试几次。直到弹出输入密码的窗口才是真的流程正确了。然后支付成功之后马上就可以收到js中的回调,这个时候你可以去处理你的订单和业务逻辑。

小结

如果是生产环境,我们需要再多个地方调用,需要再封装一下。function jsApiCall(json, success, fail) {

WeixinJSBridge.invoke( 'getBrandWCPayRequest',

json,//josn串

function (res)

{

WeixinJSBridge.log(res.err_msg); //alert(res.err_code + res.err_desc + res.err_msg);

if (res.err_msg == "get_brand_wcpay_request:ok") { //充值进去 要区分是出题充值 还是购买悬赏 前者冲到他的钱包

//后者直接冲到系统账户

if (success) success();

}

if (res.err_msg == 'get_brand_wcpay_request:cancel') { // alert('取消支付');

if (fail)fail();

}

}

);

}function callpay(json,success,fail)

{ if (typeof WeixinJSBridge == "undefined")

{

alert("请在微信中打开!"); if (document.addEventListener)

{

document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);

} else if (document.attachEvent)

{

document.attachEvent('WeixinJSBridgeReady', jsApiCall);

document.attachEvent('onWeixinJSBridgeReady', jsApiCall);

}

} else

{

jsApiCall(json, success, fail);

}

}

View Code[LoginValid] public ActionResult H5PayJson(string orederId)

{ var user = _workContext.CurrentUser; var order = _paymentService.GetOrderByOrderNumber(orederId); //判断订单是否存在 //订单是否已经支付了

var openid = user.OpenId; var jsApipay = new JsApiPayMvc(ControllerContext.HttpContext)

{

openid = openid,

total_fee = (int) order.Amount*100

}; try

{

jsApipay.GetUnifiedOrderResult(); return Json(jsApipay.GetJsApiParameters());//实际还是字符串

} catch (Exception e)

{ //统一下单失败

return Json(new PortalResult(false, e.Message));

}

}

调用的时候这样直接唤起支付了。 但如果传入的json不是json对象,微信加载动画会一直卡在哪儿。$.post("/Checkout/H5PayJson", { orederId: orderId }, function (jsondata) { var jdata = JSON.parse(jsondata); if (jdata.appId) {

callpay(jdata, function () {

$.post("/payment/WeiXinPaySuccess", { ordernumber: orderId }, function (paymentdata) { if (paymentdata.IsSuccess === true) {

submitQuestion();

} else {

$.alert(paymentdata.Message);

}

});

}, function () {

$.alert("你已取消支付!");

});

} else {

alert("统一下单失败!");

}

});

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

公众号php支付接口开发,公众号支付接口的开发相关推荐

  1. 基于vue-cli3开发微信公众号网页——调取微信分享,微信支付接口

    第一步安装微信jdk npm install weixin-js-sdk 第二步封装微信接口方法 //微信支付方法 import wx from "weixin-js-sdk"; ...

  2. 微信公众号开发,微信支付功能开发(网页JSAPI调用)

    1.微信支付的流程 如下三张手机截图,我们在微信网页端看到的支付,表面上看到的是 "点击支付按钮 - 弹出支付框 - 支付成功后出现提示页面",实际上的核心处理过程是: 点击支付按 ...

  3. 微信支付(公众号支付)微信公众平台开发教程(5)

    简介 Senparc.Weixin SDK 是由盛派网络(Senparc)团队自主研发的针对微信各模块的 开发套件(C#SDK), 已全面支持微信公众号.微信支付.企业号.开放平台.JSSDK.摇一摇 ...

  4. 微信支付、微信公众号接口认证方案

    1 微信公众号接口认证方案 1.1 认证流程 安全API接口认证方案 流程图模板_ProcessOn思维导图.流程图​www.processon.com/view/link/636e05a21e085 ...

  5. H5微信公众号开发,微信支付

    (如需完整代码,开发遇到什么问题,可与本人联系,代码给大家下载并帮你解决问题,微信号:1131237188) 1.公众号开发,首先需要微信公众号的appId,secret 相当于账号密码 2.到公众号 ...

  6. PHP 支付PC端扫码支付、APP接口调起支付宝支付、微信公众号接入支付宝支付

    第一:第三方支付原理 第二:支付接口申请流程 地址:https://docs.open.alipay.com/270/105899/ : 参考地址:https://blog.csdn.net/nove ...

  7. 微信公众帐号开发教程第2篇-开发模式启用及接口配置

    编辑模式与开发模式 微信公众帐号申请成功后,要想接收处理用户的请求,就必须要在"高级功能"里进行配置,点击"高级功能",将看到如下界面: 从上图中可以看到,高级 ...

  8. [027] 微信公众帐号开发教程第3篇-开发模式启用及接口配置

    编辑模式与开发模式 微信公众帐号申请成功后,要想接收处理用户的请求,就必须要在"高级功能"里进行配置,点击"高级功能",将看到如下界面: 从上图中可以看到,高级 ...

  9. php微信统一公众号支付接口,微信公众号支付怎么实现统一下单接口

    微信公众号支付怎么实现统一下单接口 发布时间:2021-03-12 09:44:45 来源:亿速云 阅读:89 作者:小新 这篇文章将为大家详细讲解有关微信公众号支付怎么实现统一下单接口,小编觉得挺实 ...

最新文章

  1. 基于Springboot实现田径运动会管理系统
  2. 利用构造函数进行简化类初始化
  3. 记录MySQL下所执行的所有命令
  4. ie浏览器网页版进入_Win10系统中IE和edge浏览器无法打开网页如何解决
  5. docker mysql域名访问_Docker中配置MySQL并实现远程访问
  6. STM32H7+USB3300+SD作为U盘速度慢的问题
  7. 第三次个人作业—“K米”评测
  8. 【VirtualBox虚拟机总是提示“0x00000000指令引用的0x00000000内存,该内存不能为written“错误的解决方法】
  9. Win11打开控制面板的方法
  10. 2篇SCI二区认定优秀博士!57万安家费+100万房补,浙江高校!
  11. linux sli 提高效率,两大优点!NVIDIA混合SLI功能完全解析
  12. 一个千万级大标的精彩角逐过程(进行中...)
  13. MacOS-MacAPP使用Main.storyboard启动视图程序踩坑
  14. 心理咨询服务微信小程序的设计与实现-计算机毕业设计
  15. 蓝天碧水中国梦-光伏发电(1)-光伏发电构成和产业链
  16. 数学笔记31——幂级数和泰勒级数
  17. Fiddler抓取移动端APP流量数据
  18. 电力电子技术学习笔记(2)——晶闸管
  19. 解析骁龙移动平台在AR设备中的应用实践
  20. CodeIgniter 框架使用之分页使用

热门文章

  1. 【UCOS-ii】OSTaskCreateExt与OSTaskCreate
  2. oncontextmenu 事件
  3. seaborn pairplot ax_seaborn常用的10种数据分析图表
  4. 计算机视觉实验LAB——照相机标定与位姿计算(上)
  5. 主流JSON引擎性能比较(GSON,FASTJSON,JACKSON,JSONSMART)
  6. MJUPC-006_编程挑战系列赛第六场(以代码为文,贺国庆华诞) _F.原神:原石的优惠大礼包
  7. nvidia jetson nano 风扇控制
  8. 红米note9pro和红米note8pro哪个好
  9. 金刚石图案java实现_案例1 绘制金刚石图案算法.ppt
  10. 京东售后服务认证考试