微信原生支付 Native扫码支付( V3.3.7 版本)

[尊重别人的劳动成果,转载请注明出处:一缕晨光工作室,www.wispdawn.com]

前言

辛苦研究三天,遇到各种困难,最终还是克服了,把我的理解和思路分享给需要帮助的人,如果你觉的好,请帮我分享一下,谢谢。 在没有做之前,我以为和支付宝,以及银联一样,会在官网找到相应的demo,照葫芦画瓢即可,没有什么复杂的,真正去做的时候,发现各种错误,很多时候都莫名其妙找不到北, 在网上搜了不知道多少遍,有V3版的,不过都是js api版本的,没有找到原生扫码支付,下了几个V2版本的微信支付c#demo,感觉乱糟糟的。官网只提供了一个php版本的demo 研究了一天没有结果,第二天我决定从官网的php的原生扫码支付,根据他的逻辑,用c#写出来,下面就是所有思路及代码,文章最后我放上整个解决方案压缩包。

想实现扫码支付需要三大步骤

  1. 生成二维码,二维码包含产品ID
  2. 微信公众平台->微信支付->配置支付回调URL(自己开发回调页面)
  3. 开发支付成功后通知页面

最终效果如图

下面一步一步讲解

一.生成二维码

这步骤比较简单,根据官网文档 ,需要固定的参数,其中签名算法已经写好,如下代码

下图是用于生成二维码字符串,

public string CreateQRCodeUrl(string productid)
  {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("appid", helper.GetAppId);
            dic.Add("mch_id", helper.GetMch_Id);
            dic.Add("nonce_str", TenpayUtil.getNoncestr());
            dic.Add("product_id", productid);
            dic.Add("time_stamp", TenpayUtil.getTimestamp());
            dic.Add("sign",helper.GetSign(dic));

            string url = WxPayHelper.FormatBizQueryParaMap(dic, false);//这里不要url编码
            return "weixin://wxpay/bizpayurl?" + url;
 }

生成微信二维码字符串

最终生成的url

weixin://wxpay/bizpayurl?appid=wxed94e****9b4bc&mch_id=122468****&nonce_str=877A9BA7A98F75B90A9D49F53F15A858& product_id=1&sign=B2A03B1B6583972FF67C8AD3D7414DD1&time_stamp=1420466744

有了文本想生成二维码就简单了,起初我是采用ThoughtWorks.QRCode.dll,后来发现一值报错,超出数组范围,估计是字符串太长了,最后选择使用一个开源项目 Gma.QrCodeNet.Encoding.dll,速度很快。

代码如下

 WxPayHelper helper = new WxPayHelper();
        public void ProcessRequest(HttpContext context)
        {
            if (context.Request["buynum"]!=null)
            {
                string proId ="1";//示例代码写死了,自己根据业务处理
                string qrurl = CreateQRCodeUrl(proId);

                QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H);
                Gma.QrCodeNet.Encoding.QrCode qrCode = new Gma.QrCodeNet.Encoding.QrCode();
                qrEncoder.TryEncode(qrurl, out qrCode);
                using (MemoryStream ms = new MemoryStream())
                {
                    var renderer = new GraphicsRenderer(new FixedModuleSize(4, QuietZoneModules.Two));
                    renderer.WriteToStream(qrCode.Matrix, ImageFormat.Png, ms);
                    context.Response.ContentType = "image/png";
                    context.Response.OutputStream.Write(ms.GetBuffer(), 0, (int)ms.Length);
                }
            }
        }

生成二维码

前台js调用

$(function () {
            $("#txtKey").keyup(function () {
                var num=$(this).val();//这里设置购买数量
                $("#qrDiv").html("<img src=QrCode.ashx?buynum="+num+" height=200 width=200 /> ");
            });
 });

二、写回调页面,本程序是NativeCallBack.aspx

这个页面主要任务是当扫码二维码的时候,微信向这个页面post XML数据,其中包含产品id,即二维码上的产品id ,我们需要根据产品id,查询产品名称,总价格,以及一些附属信息, 我们需要再次把这些参数post给微信统一支付接口,如果数据正确,微信会给我们生成一个prepay_id 预支付id,我们再次把prepay_id post给微信,整个流程即是这样子的,其实产品id就相当于一个订单号,唯一性,当然你也可以根据产品id,在这个页面里面下单,业务根据自己需要处理。

页面代码如下

log4net.ILog logger = WxV3.Helper.LogHelper.GetInstance().Log;
        WxV3.Helper.WxPayHelper helper = new Helper.WxPayHelper();
        protected void Page_Load(object sender, EventArgs e)
        {
            //1.接受微信平台post 过来的XML信息
            //2.验证签名,从XML中获取ProductID,获取产品信息
            //2.1设置out_trade_no,total_fee,notify_url,trade_type,product_id 参数,提交统一接口
            //3.提交统一接口后获取PrepayId
            //4.将PrepayId 和return 根据参数拼接生xml信息(其中包含生成的package参数)输出
            if (Request.RequestType == "POST")
            {
                try
                {
                    StreamReader reader = new StreamReader(Request.InputStream);
                    String xmlData = reader.ReadToEnd();
                    helper.ReceivePostXmlData(xmlData);
                    logger.Info("接收post来的xmlData=" + xmlData);
                    if (helper.CheckSign())
                    {
                        logger.Info("签名验证通过");
                        string proId = helper.GetProductId();
                        logger.Info("产品id=" + proId);

                        switch (proId)
                        {
                            case "1":

                                #region 业务处理
                                helper.SetParameter("body", "一缕晨光CMS系统");
                                helper.SetParameter("out_trade_no", DateTime.Now.ToString("yyyyMMddHHmmss") + CommonUtil.BuildRandomStr(4));
                                helper.SetParameter("total_fee", "88800");//这里单位是分
                                helper.SetParameter("notify_url", "http://www.wispdawn.com/WxV3/NativeNotify.aspx");
                                helper.SetParameter("trade_type", "NATIVE");
                                string prepay_id = helper.GetPrepayId();
                                logger.Info("prepay_id=" + prepay_id);
                                if (!string.IsNullOrEmpty(prepay_id))
                                {
                                    helper.SetReturnParameter("return_code", "SUCCESS");
                                    helper.SetReturnParameter("result_code", "SUCCESS");
                                    helper.SetReturnParameter("prepay_id", prepay_id);
                                    helper.SetReturnParameter("appid", helper.GetAppId);
                                    helper.SetReturnParameter("mch_id", helper.GetMch_Id);
                                    helper.SetReturnParameter("nonce_str", TenpayUtil.getNoncestr());
                                }
                                else
                                {
                                    helper.SetReturnParameter("return_code", "SUCCESS");//返回状态码
                                    helper.SetReturnParameter("result_code", "FAIL");//业务结果
                                    helper.SetReturnParameter("err_code_des", "预订单生产失败");
                                }
                                #endregion

                                break;
                            default:
                                helper.SetReturnParameter("return_code", "SUCCESS");//返回状态码
                                helper.SetReturnParameter("result_code", "FAIL");//业务结果
                                helper.SetReturnParameter("err_code_des", "此商品无效");//业务结果
                                break;
                        }
                    }
                    else
                    {
                        helper.SetReturnParameter("return_code", "FAIL");
                        helper.SetReturnParameter("return_msg", "签名失败");
                        logger.Info("签名验证没有通过");
                    }
                    string xmlStr = helper.GetReturnXml();
                    logger.Info("返回xml=" + xmlStr);
                    Response.ContentType = "text/xml";
                    Response.Clear();
                    Response.Write(xmlStr);
                    Response.End();
                }
                catch (Exception ex)
                {
                    logger.Error("异常了", ex);
                }
            }
        }

NativeCallBack代码

三、支付通知页面,本程序 NativeNotify.aspx

这个页面用来处理成功通知的,微信把交易的结果依xml形式post该页面,当你收到消息后,如果成功了,你可以根据此来修改数据库,或者更新状态,等等。我做到这步时候,需要实现扫码二维码,支付成功后,3秒后调整, 实现思路是这样的,在二维码页面,setinterval get后台数据库是否已经支付,如果已经支付则执行settimeout 3秒后调整到成功页面。目前我是这样实现的,不知道别人怎么实现的。

通知代码如下。

  log4net.ILog logger = WxV3.Helper.LogHelper.GetInstance().Log;
        WxV3.Helper.WxPayHelper helper = new Helper.WxPayHelper();
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.RequestType == "POST")
            {
                try
                {
                    StreamReader reader = new StreamReader(Request.InputStream);
                    String xmlData = reader.ReadToEnd();
                    helper.ReceivePostXmlData(xmlData);
                    logger.Info("Notify_接收post来的xmlData=" + xmlData);
                    if (helper.CheckSign())
                    {
                        Dictionary<string, string> dicBack = helper.GetParameter();//获取所有参数
                        if (dicBack!=null&&dicBack.Keys.Contains("return_code"))
                        {
                            if (dicBack["return_code"] == "SUCCESS")
                            {
                                logger.Info("return_code=SUCCESS");
                                if (dicBack["result_code"]=="SUCCESS")
                                {
                                    logger.Info("result_code=SUCCESS");
                                    string out_trade_no = dicBack["out_trade_no"];//商户订单号
                                    logger.Info("out_trade_no="+out_trade_no);

                                    //1.验证商户订单号是否被处理
                                    //2.处理过直接返回成功,否则返回
                                    //此处根据out_trade_no 处理业务数据

                                    //处理业务数据结束

                                    logger.Info("Notify_验证签名成功");
                                    helper.SetReturnParameter("return_code", "SUCCESS");
                                    helper.SetReturnParameter("return_msg", "");
                                }
                            }
                            if (dicBack["return_code"]=="FAIL")
                            {
                                logger.Info("Notify_验证签名成功");
                                helper.SetReturnParameter("return_code", "SUCCESS");
                                helper.SetReturnParameter("return_msg", dicBack["return_msg"]);
                            }
                        }
                    }
                    else
                    {
                        logger.Info("Notify_验证签名失败");
                        helper.SetReturnParameter("return_code", "FAIL");
                        helper.SetReturnParameter("return_msg", "签名失败");
                    }
                    string xmlStr = helper.GetReturnXml();
                    logger.Info("Notify_返回xml=" + xmlStr);
                    Response.ContentType = "text/xml";
                    Response.Clear();
                    Response.Write(xmlStr);
                    Response.End();
                }
                catch (Exception ex)
                {
                    logger.Error("Notify_异常了", ex);
                }
            }
        }

NativeNotify页面代码

如果你也是需要扫描原生支付,可以直接下载本解决方案,只需要把 WxPayHelper构造函数中的参数修改下即可使用

 public WxPayHelper()
        {
            this.parameters = new Dictionary<string, string>();
            this.returnParameter = new Dictionary<string, string>();
            this.appid = "wxed94e6985d29****";//appid
            this.mch_id = "122468****";      //微信支付商户号
            this.PartnerKey = "ASD2Ssaghh3df4570erdssd4we33****";//这里是商户的partnerkey
        }

本文主要讲解整个思路,详细请看代码,点击下载本解决方案

尊重别人的劳动成功,转载请注明出处:一缕晨光工作室,www.wispdawn.com

时间: 2024-12-08 18:35:03

微信原生支付 Native扫码支付( V3.3.7 版本)的相关文章

微信支付Native扫码支付模式二之CodeIgniter集成篇

微信支付API类库来自:https://github.com/zhangv/wechat-pay 请先看一眼官方场景及支付时序图:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5 官方API列表:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1 二维码生成类库:phpqrcode 走了几天的弯路,直到遇到Lamtin指点(热心网友),他说你既然是集成

微信支付之扫码支付相关代码(Java)

最近开发网站过程,需要引入支付过程,第三方支付中最火的莫过于支付宝支付和微信支付,下边借助微信支付官网上的文档,写一下接入微信支付之扫码支付的流程 相对支付宝支付而言,微信支付的开发文档写的相当的low,demo写的一点都不简洁,下边写一下微信扫码支付的过程,这一过程中,需要注意的所涉及的实际业务是怎样的,根据实际情况结合业务进行引入,在进入正式开发之前,要申请微信支付的相关内容按照官网的操作进行即可,审核成功后,会得到appId,商户号,商户平台登录账号和密码 登录微信支付官网 https:/

微信支付之扫码支付、公众号支付、H5支付、小程序支付相关业务流程分析总结

前言 很久以来,一直想写一篇微信支付有关的总结文档:一方面是总结自己的一些心得,另一方面也可以帮助别人,但是因种种原因未能完全理解透彻微信支付的几大支付方式,今天有幸做一些总结上的文章,也趁此机会,将一年多以来的相关经验分享一下. 概述 1. 扫码支付 商户在pc端展示一个支付二维码,用户使用微信扫一扫功能,扫码后实现付款的支付方式. 2. 公众号支付 商户在微信APP内(微信浏览器)打开H5网页,通过微信支付实现付款的支付方式. 3. H5支付 商户在微信浏览器以外的手机浏览器打开H5网页,通

怎么对接个人收款支付接口(扫码支付)

怎么对接个人收款支付接口(扫码支付) 实现个人收款是一件很麻烦的事,可以通过PAYJX 支付平台 注册个人收款接口,帮助签约个人支付宝,微信支付接口(不需要营业执照),几分钟就可以开通,申请开通后,获取商户号和通信密钥,然后开始对接,上一章讲了收银台模式支付,本章主要说一下扫码支付 扫码支付请求步骤: 构建请求参数 POST 参数到请求地址 根据返回内容展示二维码 用户支付成功后接收异步通知 扫码对接 php代码如下: <?php $order = [ 'mchid' => 'xxxxxxxx

支付宝支付之扫码支付(电脑网站支付)、H5支付(手机网站支付)相关业务流程分析总结

前言 在上一篇文章<微信支付之扫码支付.公众号支付.H5支付.小程序支付相关业务流程分析总结>中,分析和总结了微信支付相关支付类型的业务流程,这里作为与微信支付平起平坐不相伯仲的支付宝支付,当然也是每个公司少不了的第三方支付接入选择. 因此,本篇文章主要分析和总结支付宝支付中的扫码支付.H5支付相关业务流程. 概述 1. 电脑网站支付 电脑网站支付,也称扫码支付,是专门针对电脑而开发的一种支付方式,既在网页展示一个动态生成的支付二维码,用户通过手机支付宝扫码以后可实现支付功能的一种支付方式.

支付宝支付开发—当面付条码支付和扫码支付

关键字:支付宝 当面付 条码支付 扫码支付 二维码支付 订单查询 退款作者:方倍工作室 本文介绍支付宝中当面付下属的条码支付.扫码支付.订单查询.退款申请的集成开发过程. 本文分为以下五个部分: 条码支付和扫码支付介绍 申请应用 密钥生成及配置 API及SDK集成 条码支付.扫码支付.订单查询.退款申请 一.条码支付及二维码支付介绍 1. 条码支付 条码支付是支付宝给到线下传统行业的一种收款方式.商家使用扫码枪等条码识别设备扫描用户支付宝钱包上的条码/二维码,完成收款.用户仅需出示付款码,所有收

支付宝支付开发——当面付条码支付和扫码支付

关键字:支付宝 当面付 条码支付 扫码支付 二维码支付 订单查询 退款作者:方倍工作室原文: http://www.cnblogs.com/txw1958/p/alipay-f2fpay.html 本文介绍支付宝中当面付下属的条码支付.扫码支付.订单查询.退款申请的集成开发过程. 本文分为以下五个部分: 条码支付和扫码支付介绍 申请应用 密钥生成及配置 API及SDK集成 条码支付.扫码支付.订单查询.退款申请 注: 支付宝支付开发有一定的门槛,如果您愿意为知识付费来节省您宝贵的时间,请直接见底

微信支付之扫码支付(java版 native原生支付)

本文直接从代码调用微信扫码支付讲起.账号配置,参数生成等请参考官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1 微信扫码支付.简单来说,就是你把微信支付需要的信息,生成到二维码图片中.通过微信扫一扫,发起支付.我们需要做的就是二件事: 一是:按照微信扫码支付规则生成二维码信息. 二是:微信没有提供生成二维码图片的接口.需要我们自己把二维码信息生成到二维码图片中. 1.模式选择: 微信扫码支付,有两种模式,文档中有

微信支付公的众号支付和扫码支付

公众号支付是手机端的微信公众号H5页面支付,这种支付方式必须是在微信内置浏览器发起. 扫码支付分为模式一和模式二,模式一主要为线下服务,该模式是先扫码,再生成订单,商户先为自己的商品生成二维码连接,然后用户扫码之后决定是否购买,二维码无过期时间,比如自动售卖机大多采用这种模式:模式二主要为线上电商服务,用户选择商品后生成订单,根据订单生成二维码,然后支付,该二维码为临时二维码. 开发流程 一.授权目录 官方文档说必须是精确目录,其实是二级或三级目录就可以了,太精确的可能还会出现不识别的情况.如果