产品要求用户通过其他用户的推荐二维码进入小程序,并且绑定二维码所带的参数
微信小程序的二维码生成分为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(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参数的时候,怎么请求都是错误的数据。百度发现这个参数是多余的!!多余的!!多余的!!是不需要的,不加这个就好了。
最后最后!还是想到之前走的那个人说,一入小程序,放眼望去,全是坑!!!!!!不对!!!一入微信全是坑,公众号那玩意儿也是!!!