正文转自:https://www.cnblogs.com/onetwo/p/6667424.html

柜日前以做微信小程序,被分配到做开发就等同块,现在针对就无异片做一个略的总及梳理。

支出,对于购物来说,可以说凡是占了生关键的一致块,毕竟能够接纳钱才是重大。

当在开发前,我们要出下这些事物:

  • appId
  • 密钥(小程序配置界面)
  • 商户号
  • api密钥(商家后台自己安装)

当然这些是无须我们好报名之,公司会有人申请好,然后一旦什么和这个人口说,让他供就足以了。

先是来拘禁一下官方给来之业务流程时序图

 

本条图很清晰的表达了以多少序开发被之全体流程,每一样步要召开来什么。

一个总体的开,一般景象下都是含了下三单关键的接触;

  • 付出(正常是出平台供的h5页面被用户操作,主要是输密码)
  • 照会(用户完成同样笔画支付了,支付平台要通公司开结果,商家收取结果后展开部分相应的处理)
  • 查询(与亚点出接触转的意思,商家自己积极去出平台查询支付的结果,然后根据结果召开相应的拍卖)

下面就是重要来大概实现转上面说之首先触及,支付,也是可展开下两步之以大前提。

付出的大概实现

稍序的兑现

简起见,在index.wxml中补充加一个输入框和一个button,绑定一下应和的风波,输入框主要是用以输入订单号,按钮用于模拟提交一个订单并发起支付。

<!--index.wxml-->
<view class="container">
    <input type="text" bindinput="getOrderCode" style="border:1px solid #ccc;"  />
    <button bindtap="pay">立即支付</button>
</view>

然后以index.js中描绘及等同有点截代码,主要是拍卖点按钮的点击事件。

Page({
    data: {
        txtOrderCode: ''
    },
    pay: function () {
        var ordercode = this.data.txtOrderCode;
        wx.login({
          success: function (res) {
            if (res.code) {
              wx.request({
                url: 'https://www.yourdomain.com/pay',
                data: {
                  code: res.code,//要去换取openid的登录凭证
                  ordercode: ordercode
                },
                method: 'GET',
                success: function (res) {
                  console.log(res.data)
                  wx.requestPayment({
                    timeStamp: res.data.timeStamp,
                    nonceStr: res.data.nonceStr,
                    package: res.data.package,
                    signType: 'MD5',
                    paySign: res.data.paySign,
                    success: function (res) {
                      // success
                      console.log(res);
                    },
                    fail: function (res) {
                      // fail
                      console.log(res);
                    },
                    complete: function (res) {
                      // complete
                      console.log(res);
                    }
                  })
                }
              })
            } else {
              console.log('获取用户登录态失败!' + res.errMsg)
            }
          }
        });
    },
    getOrderCode: function (event) {
        this.setData({
          txtOrderCode: event.detail.value
        });
    }
})

好看看,在此地Catcher先通过wx.login斯API先取到了登录的凭证code,并将这凭证code做也请参数用wx.request其一API发起一个网要。

以是网络要处理后会见返回小序开发所用的连锁参数。拿到这些参数后,再调用wx.requestPayment斯开API,此时才好不容易真正的倡导支付。

时至今日,小程序及时边的转业都做得了了,接下去就是如果失去处理接口那边的事了,其实接口要开的即是回来小序需要之几个参数。但是若以到当时几乎只参数还是待做过多政工的。

接口的贯彻

依据最新版本的Senparc.Weixin.MP既开发了略微序相关的情节,但是商家之所以之本要比较小

还要近期吗从不打算对这组件进行升级。所以就打白纸一张开始了。

为此之是mvc,所以是有些序发起的纱要会由于下的action的执行,里面的落实,每一样步做了什么该吗早就非常清晰了。

public ActionResult Pay(string code, string ordercode)
{
    var paramter = new Parameters();
    paramter.out_trade_no = ordercode;

    //使用登录凭证 code 获取 session_key 和 openid
    var unifiedorderRes = GetOpenIdAndSessionKey(paramter.appid, paramter.secret, code);

    //反序列化session_key 和 openid成ChangeResponseEntity实体
    var tmp = JsonConvert.DeserializeObject<ChangeResponseEntity>(unifiedorderRes);

    //统一下单的url和参数
    var payUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    var param = GetUnifiedOrderParam(tmp.openid, paramter);

    //统一下单后拿到的xml结果
    var payResXML = Helper.DoPost(param, payUrl);
    var payRes = XDocument.Parse(payResXML);
    var root = payRes.Element("xml");

    //序列化相应参数返回给小程序
    var res = GetPayRequestParam(root, paramter.appid, paramter.key);
    return Json(res, JsonRequestBehavior.AllowGet);            
}

由于单独是一个演示的进程,不思这些多少常常为字符串的花样反复发本代码中,所以管相关的参数全部还放至了一个叫做也Parameters的类中(放到配置文件被吗是足以的),除了订单号是从小程序传过来的,当然在其实中立即是无客观的,毕竟像金额这些事物,不容许每次都是和一个!这点是一旦留意的。

下先来探这Parameters类的概念:

public class Parameters
{      
    public string appid { get { return "申请的appid"; } }
    public string mchid { get { return "申请的商户号"; } }
    public string nonce { get { return Helper.GetNoncestr(); } }
    public string notify_url { get { return "http://yourdomain.com/notifyurl"; } }
    public string body { get { return "testpay"; } }
    public string out_trade_no { get; set; }
    public string spbill_create_ip { get { return "IP地址"; } }
    public string total_fee { get { return "1"; } }
    public string trade_type { get { return "JSAPI"; } }
    public string key { get { return "在商家后台设置的密钥"; } }
    public string secret { get { return "在配置小程序时的密钥"; } }
}

率先是获取到登录凭证后发起的是网络要。这个网络要是决定了这次支付是否得逞的第一步!

下面要做的是为此登录凭证去更换我们若之openid。

/// <summary>
/// 取openid和session_key
/// </summary>
/// <param name="appid"></param>
/// <param name="secret"></param>
/// <param name="js_code"></param>
/// <returns></returns>
private string GetOpenIdAndSessionKey(string appid, string secret, string js_code)
{
    var url = string.Format("https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code"
        , appid,secret,js_code);
    var request = WebRequest.Create(url) as HttpWebRequest;

    var response = url.GetResponse();
    var respStream = response.GetResponseStream();

    var res = string.Empty;
    using (var reader = new StreamReader(respStream, Encoding.UTF8))
    {
        res = reader.ReadToEnd();
    }
    return res;
}

苟换取openid,就要向微信提供的地址发起一个网络要,并于URL带上appid,secret和凭证code这三独参数。

接下来就得以到一个底形式之json字符串

{
  "openid": "OPENID",
  "session_key": "SESSIONKEY"
}

将到以后自然就是若对准斯字符串进行json的反序列化,这里运用了json.net这个保险。

据悉时序图,下面要调用统一下单这个接口了。

地方的代码,在联合下仅就同片,又分为底几乎独步骤

  1. 处理统一下单的参数(签名以及组装xml)
  2. 发起POST请求
  3. 浅析呼吁得到的结果

参数的处理:

具体规则参见:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3

/// <summary>
/// 取统一下单的请求参数
/// </summary>
/// <param name="openid"></param>
/// <param name="param"></param>
/// <returns></returns>
private string GetUnifiedOrderParam(string openid, Parameters param)
{            
    //参与统一下单签名的参数,除最后的key外,已经按参数名ASCII码从小到大排序
    var unifiedorderSignParam = string.Format("appid={0}&body={1}&mch_id={2}&nonce_str={3}&notify_url={4}&openid={5}&out_trade_no={6}&spbill_create_ip={7}&total_fee={8}&trade_type={9}&key={10}"
        , param.appid, param.body, param.mchid, param.nonce, param.notify_url
        , openid, param.out_trade_no, param.spbill_create_ip, param.total_fee, param.trade_type, param.key);
    //MD5
    var unifiedorderSign = Helper.GetMD5(unifiedorderSignParam).ToUpper();
    //构造统一下单的请求参数
   return string.Format(@"<xml>
                                <appid>{0}</appid>                                              
                                <body>{1}</body>
                                <mch_id>{2}</mch_id>   
                                <nonce_str>{3}</nonce_str>
                                <notify_url>{4}</notify_url>
                                <openid>{5}</openid>
                                <out_trade_no>{6}</out_trade_no>
                                <spbill_create_ip>{7}</spbill_create_ip>
                                <total_fee>{8}</total_fee>
                                <trade_type>{9}</trade_type>
                                <sign>{10}</sign>
                               </xml>
                    ", param.appid, param.body, param.mchid, param.nonce, param.notify_url, openid
                     , param.out_trade_no, param.spbill_create_ip, param.total_fee, param.trade_type, unifiedorderSign);

}

此要注意一点,由于我们的招的trade_type是JSAPI,所以这里不可不是若增长openid进行拍卖的。

接下来就解析统一下只有回的XML了,说是解析,其实也即是若将到我们需要的数量罢了。这里最后会收获一个稍程序开发API需要之参数实体。

/// <summary>
/// 获取返回给小程序的支付参数
/// </summary>
/// <param name="root"></param>
/// <param name="appid"></param>
/// <param name="key"></param>
/// <returns></returns>
private PayRequesEntity GetPayRequestParam(XElement root,string appid,string key)
{              
    //当return_code 和result_code都为SUCCESS时才有我们要的prepay_id
    if (root.Element("return_code").Value == "SUCCESS" && root.Element("result_code").Value == "SUCCESS")
    {
        var package = "prepay_id=" + root.Element("prepay_id").Value;
        var nonceStr = Helper.GetNoncestr();
        var signType = "MD5";
        var timeStamp = Convert.ToInt64((DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds).ToString();

        var paySignParam = string.Format("appId={0}&nonceStr={1}&package={2}&signType={3}&timeStamp={4}&key={5}",
             appid, nonceStr, package, signType, timeStamp, key);

        var paySign = Helper.GetMD5(paySignParam).ToUpper();

        var payEntity = new PayRequesEntity
        {
            package = package,
            nonceStr = nonceStr,
            paySign = paySign,
            signType = signType,
            timeStamp = timeStamp
        };
        return payEntity;
    }

    return new PayRequesEntity();
}

开发参数实体对应的情如下:

/// <summary>
/// 小程序支付需要的参数
/// </summary>
public class PayRequesEntity
{
    /// <summary>
    /// 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
    /// </summary>
    public string timeStamp { get; set; }

    /// <summary>
    /// 随机字符串,长度为32个字符以下。
    /// </summary>
    public string nonceStr { get; set; }

    /// <summary>
    /// 统一下单接口返回的 prepay_id 参数值
    /// </summary>
    public string package { get; set; }

    /// <summary>
    /// 签名算法
    /// </summary>
    public string signType { get; set; }

    /// <summary>
    /// 签名
    /// </summary>
    public string paySign { get; set; }
}

要小心的凡,这里的签署操作,一定是一旦配合appId,这也是Catcher在支付即时同样块踩的唯一的一个坑,所以提示一下各位读者,希望会躲过这坑。

再有最后一步就是是如果回一个序列化的目标为多少序,以供小程序下。

暨这里,后台接口也都OK了,现在虽因故真机扫描二维码,点击即支付按钮,此时即令会见弹来而而输入密码的规模,输入你的微信支付密码,如下所示:

json 1

接下来就会见唤起支付成功,如下所示:

json 2

几乎秒钟后虽会见吸纳微信支付发来的消息,通知你于啊时支出了有点钱。

json 3

通之略说明

前吧关系了,通知是用户支出成功后,微信的劳务器会向我们归总下单指定的notify_url倡议一个异步的回调。

下用伪代码来表示即同样历程

public ActionResult Notify()
{
    //1.获取微信通知的参数

    //2.更新订单的相关状态

    //3.返回一个xml格式的结果给微信服务器
    var res = @"<xml>
          <return_code><![CDATA[SUCCESS]]></return_code>
          <return_msg><![CDATA[OK]]></return_msg>
        </xml>";

    return Content(res);
}

此地用注意的凡如处理好微信重通知之情形!

查询的简说明

通告和查询本质上还是怀念清楚订单是否出成功了。

它们的别是:通知是微信主动通报企业; 查询是店主动向微信发起查询;

当时点儿个动作的基点是不相同的。

当微信会正常发起推送并且公司收取这推送的服务器又从不悬挂的当儿,查询的图是硕果仅存的。

自然,不可避免的会晤现出,微信不可知健康发起推送或者商店的服务器挂了,这个时节查询的意就转换得挺重大了!!

这上我们便设建交起一个定时作业来特别处理这种情况了,可以选取Quartz.NetHangfire等!

是作业的情具体如下:

public void QueryJob()
{ 
    //1.找到要查询的订单号

    //2.根据订单号和appId等内容向https://api.mch.weixin.qq.com/pay/orderquery这个地址发起网络请求

    //3.拿到微信返回的结果

    //4.根据结果进行相应的处理
}

有关多久执行同样糟糕是作业,可能就如依据使用小程序进行购物的多寡多不多来开一个盖的估算。

总结

稍许序的付出或者算比较简单,毕竟文档还算齐全,基本照着文档的提拔就能够将这开做好。

每日进步一点点

 

 

分类: 小程序

 

相关文章

网站地图xml地图