隐藏

c# 微信小程序B接口获取小程序二维码

发布:2022/3/26 17:21:38作者:管理员 来源:本站 浏览次数:1396


一入微信,满地是坑,这个坑,你得一个个填过去。




产品要求用户通过其他用户的推荐二维码进入小程序,并且绑定二维码所带的参数


微信小程序的二维码生成分为A接口和B接口:


这是微信的官方文档介绍(文档链接如下https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/qr-code.html)


A接口上限是10W个,B接口没有上限


对于这个应用场景,我选择了B接口生成小程序码




首先我们要获取到申请接口所有用的assess_token(附上官方文档https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html)


通过GET请求到access_token,因为我们前端、API、后台都需要用到access_token,所以是将其产生时间和token保存在数据库中


   public static AccessToken GetACCESS_TOKEN(AccessToken model)

           {

               try

               {

                   //token 使用时效为2小时, 5分钟的过期时间是前后两个都能用

                   if (model.access_token_time.AddSeconds(model.expires_in - 5) > DateTime.Now)

                   {

                       return model;

                   }

   

                   #region 调用 ACCESS_TOKEN 接口

                   //拼接URL

                   string url = "https://api.weixin.qq.com/cgi-bin/token";

                   url += "?grant_type=client_credential";

                   url += "&appid=" + WxConfig.APPID;//小程序APPID

                   url += "&secret=" + WxConfig.APPSECRET;//小程序APPSECRET

                   Uri address = new Uri(url);

                   HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;

                   request.Method = "GET";

                   request.ContentType = "application/x-www-form-urlencoded";

                   request.Timeout = 6000;

   

                   #endregion

   

                   #region 反馈

   

                   using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)

                   {

                       StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);

                       string retString = reader.ReadToEnd();

                       reader.Close();

                       JavaScriptSerializer _serializer = new JavaScriptSerializer();

                       AccessToken accessToken = _serializer.Deserialize<AccessToken>(retString);

                       if (accessToken.access_token != null)

                       {

                           model.access_token = accessToken.access_token;

                           model.expires_in = accessToken.expires_in;

                           model.access_token_time = DateTime.Now;

                           model.Changed = true;

                           return model;

                       }

                   }

   

                   #endregion

               }

               catch (Exception e)

               {

                   Log.Error("WxApi", "GetACCESS_TOKEN : " + e.Message);

               }

   

               return null;

           }


创建了UnlimitedQRCodeModel类


   public class UnlimitedQRCodeModel

       {

   

           public string scene { get; set; }

   

           public string page { get; set; }

       }


并在功能模块进行小程序码获取、保存


   AccessToken accessToken = _accessTokenService.GetFirst();

                       accessToken.Changed = false;

                       accessToken = WxApi.GetACCESS_TOKEN(accessToken);

                       if (accessToken != null && accessToken.access_token != null)

                       {

                           if (accessToken.Changed)

                           {

                               _accessTokenService.Update(accessToken);

                           }

                           //创建实例

                           UnlimitedQRCodeModel qrcodeModel = new UnlimitedQRCodeModel

                           {

                               page = "pages/mobile_add/mobile_add",

                               scene = "recommendId=" + model.Id

                           };

                           //微信请求小程序码的url

                           string url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken.access_token;

                           //转换为JSON字符串

                           JavaScriptSerializer jss = new JavaScriptSerializer();

                           string json = jss.Serialize(qrcodeModel);

                           //获取post返回的二进制流

                           byte[] response = HttpService.CreateQRCode(json, url, false, 6);

                           //将二进制流保存为png图片,返回保存路径

                           var filePath = UploadHelper.SavePng(response, imagePathPrefix);

                           if (filePath != null)

                           {

                               //业务代码

                           }

                       }


    public static byte[] CreateQRCode(string xml, string url, bool isUseCert, int timeout)

           {

               System.GC.Collect();//垃圾回收,回收没有正常关闭的http连接

   

               byte[] result = null;//返回结果

   

               HttpWebRequest request = null;

               HttpWebResponse response = null;

               Stream reqStream = null;

   

               try

               {

                   //设置最大连接数

                   ServicePointManager.DefaultConnectionLimit = 200;

                   //设置https验证方式

                   if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))

                   {

                       ServicePointManager.ServerCertificateValidationCallback =

                               new RemoteCertificateValidationCallback(CheckValidationResult);

                   }

   

                   /***************************************************************

                   * 下面设置HttpWebRequest的相关属性

                   * ************************************************************/

                   request = (HttpWebRequest)WebRequest.Create(url);

   

                   request.Method = "POST";

                   request.Timeout = timeout * 1000;

   

                   //设置POST的数据类型和长度

                   request.ContentType = "text/xml";

                   byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);

                   request.ContentLength = data.Length;

   

                   //是否使用证书

                   if (isUseCert)

                   {

                       string path = HttpContext.Current.Request.PhysicalApplicationPath;

                       X509Certificate2 cert = new X509Certificate2(path + WxConfig.SSLCERT_PATH, WxConfig.SSLCERT_PASSWORD);

                       request.ClientCertificates.Add(cert);

                       Log.Debug("WxPayApi", "PostXml used cert");

                   }

   

                   //往服务器写入数据

                   reqStream = request.GetRequestStream();

                   reqStream.Write(data, 0, data.Length);

                   reqStream.Close();

   

                   //获取服务端返回

                   response = (HttpWebResponse)request.GetResponse();

   

                   //获取服务端返回数据

                   Stream sr = response.GetResponseStream();

                   result = StreamToBytes(sr);

                   if (sr != null) sr.Close();

               }

               catch (System.Threading.ThreadAbortException e)

               {

                   System.Threading.Thread.ResetAbort();

               }

               catch (WebException e)

               {

   

                   throw new WxPayException(e.ToString());

               }

               catch (Exception e)

               {

                   throw new WxPayException(e.ToString());

               }

               finally

               {

                   //关闭连接和流

                   if (response != null)

                   {

                       response.Close();

                   }

                   if (request != null)

                   {

                       request.Abort();

                   }

               }

               return result;

           }


   public static string SavePng(byte[] file, string filePath)

           {

               try

               {

                   var appPath = GetAppPath();

                   appPath += filePath;

                   if (!Directory.Exists(appPath))

                   {

                       DirectoryInfo dir = new DirectoryInfo(appPath);

                       dir.Create();

                   }

                   var fileName = Guid.NewGuid().ToString("N") + ".png";

                   File.WriteAllBytes(Path.Combine(appPath, fileName), file);

   

                   return filePath + "/" + fileName;

               }

               catch

               {

                   return null;

               }

           }


至此小程序码获取成功了,也保存到了对应路径。



注意!!!以下问题


小程序必须是通过审核的!


二维码的页面路径必须是已经发布的


在使用B接口的时候PAGE参数不要带参数,参数需要存放在scene中


记得!记得!记得!在小程序后台开发设置里面配置链接二维码打开小程序!!




在这过程中,碰到了一个很坑的问题,发现保存的图片都是异常、无法打开的。


在官方文档里请求参数里加了access_token,一开始也疑惑,明明URL上带了,为什么请求里还有加,以为是微信的要求。但是在UnlimitedQRCodeModel实例中加入access_token参数的时候,怎么请求都是错误的数据。百度发现这个参数是多余的!!多余的!!多余的!!是不需要的,不加这个就好了。




最后最后!还是想到之前走的那个人说,一入小程序,放眼望去,全是坑!!!!!!不对!!!一入微信全是坑,公众号那玩意儿也是!!!