.NET生成微信小程序推广二维码
前言
对于小程序大家可能都非常熟悉了,随着小程序的不断普及越来越多的公司都开始推广使用起来了。今天接到一个需求就是生成小程序码,并且与运营给的推广图片合并在一起做成一张漂亮美观的推广二维码,扫码这种二维码就可以进入小程序。为了节省服务器内存资源,我想的就是成功调用通微信生成小程序码的接口后直接把微信返回过来的图片二进制内容(返回的图片 Buffer)转化为二进制byte[]文件流,然后再转成Image这样就不需要在保存到本地直接读取本地的背景图片通过GDI+(Graphics)绘制图片。
选择小程序码生成方式
首先微信小程序官方文档提供了三种生成小程序码的方法,如下所示(本文采用的是第三种,需要的码数量极多的业务场景):
文档详情地址:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/qr-code/getQRCode.html
1、createwxaqrcode获取小程序二维码,适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制。
2、getwxacode获取小程序码,适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制。
3、getwxacodeunlimit获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制。
获取小程序全局唯一后台接口调用凭据(access_token)
对接开发过微信相关的业务的同学应该都清楚,调用微信接口很多情况下都会需要使用到access_token接口调用凭证。一般来说access_token的有效时长为2小时,为了不频繁调用该接口我们可以通过缓存的方法把调用凭证存起来并设置合理的过期时间(redis,cookie,memorycache都是非常不错的选择)。
文档详情地址:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html
请求接口
GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
请求参数
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
| grant_type | string | 是 | 填写 client_credential |
| appid | string | 是 | 小程序唯一凭证,即 AppID,可在「微信公众平台 - 设置 - 开发设置」页中获得。(需要已经成为开发者,且账号没有异常状态) |
| secret | string | 是 | 小程序唯一凭证密钥,即 AppSecret,获取方式同 appid |
返回参数
| 属性 | 类型 | 说明 |
|---|---|---|
| access_token | string | 获取到的凭证 |
| expires_in | number | 凭证有效时间,单位:秒。目前是7200秒之内的值。 |
access_token 的存储与更新
access_token的存储至少要保留 512 个字符空间;access_token的有效期目前为 2 个小时,需定时刷新,重复获取将导致上次获取的access_token失效;- 建议开发者使用中控服务器统一获取和刷新
access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务; access_token的有效期通过返回的expires_in来传达,目前是7200秒之内的值,中控服务器需要根据这个有效时间提前去刷新。在刷新过程中,中控服务器可对外继续输出的老access_token,此时公众平台后台会保证在5分钟内,新老access_token都可用,这保证了第三方业务的平滑过渡;access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。
详情可参考微信公众平台文档 《获取access_token》
请求示例代码
/// <summary>
/// 获取小程序全局唯一后台接口调用凭据(access_token)
/// </summary>
/// <returns></returns>
public string GetWechatAccessToken()
{
var appId = "你的小程序AppID";//小程序唯一凭证,即 AppID
var secret = "你的小程序AppSecret"; //小程序唯一凭证密钥,即 AppSecret
string Url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appId, secret);
string Result = HttpWebRequest(Url, "GET", "", Encoding.UTF8);
var obj = JsonConvert.DeserializeObject<AccessToken>(Result);
if (obj != null && obj.access_token != null)
{
return obj.access_token;
}
else
{
return "";
}
}
/// <summary>
/// WebRequest网络请求
/// </summary>
/// <param name="requestUrl">请求地址</param>
/// <param name="method">请求方式(GET/POST)</param>
/// <param name="data">请求参数(method="POST"需要携带)</param>
/// <param name="encoding">字符编码</param>
/// <param name="contentType">请求数据的内容类型</param>
/// <returns></returns>
public string HttpWebRequest(string requestUrl, string method, string data, Encoding encoding,string contentType="application/json;charset=UTF-8")
{
WebRequest webRequest = WebRequest.Create(requestUrl);
webRequest.Method = method;
if (method == "POST")
{
byte[] bytes = Encoding.Default.GetBytes(data);
webRequest.ContentType = contentType;
webRequest.ContentLength = bytes.Length;
Stream requestStream = webRequest.GetRequestStream();
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
}
WebResponse response = webRequest.GetResponse();
Stream responseStream = response.GetResponseStream();
if (responseStream == null)
{
return "";
}
StreamReader streamReader = new StreamReader(responseStream, encoding);
string result = streamReader.ReadToEnd();
responseStream.Close();
streamReader.Close();
return result;
}
/// <summary>
/// 响应模型
/// </summary>
public class AccessToken
{
/// <summary>
/// 获取到的凭证
/// </summary>
public string access_token { get; set; }
/// <summary>
/// 凭证有效时间,单位:秒。目前是7200秒之内的值
/// </summary>
public int expires_in { get; set; }
/// <summary>
/// 错误码
/// </summary>
public int errcode { get; set; }
/// <summary>
/// 错误信息
/// </summary>
public string errmsg { get; set; }
}
小程序码获取
请求地址
POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
请求参数
| 属性 | 类型 | 必填 | 说明 | |
|---|---|---|---|---|
| access_token | string | 是 | 接口调用凭证,该参数为 URL 参数,非 Body 参数。使用getAccessToken 或者 authorizer_access_token | |
| scene | string | 是 | 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) | |
| page | string | 否 | 默认是主页,页面 page,例如 pages/index/index,根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面。scancode_time为系统保留参数,不允许配置 | |
| check_path | bool | 否 | 默认是true,检查page 是否存在,为 true 时 page 必须是已经发布的小程序存在的页面(否则报错);为 false 时允许小程序未发布或者 page 不存在, 但page 有数量上限(60000个)请勿滥用。 | |
| env_version | string | 否 | 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。 | |
| width | number | 否 | 默认430,二维码的宽度,单位 px,最小 280px,最大 1280px | |
| auto_color | bool | 否 | 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调,默认 false | |
| line_color | object | 否 | 默认是{"r":0,"g":0,"b":0} 。auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示 | |
| is_hyaline | bool | 否 | 默认是false,是否需要透明底色,为 true 时,生成透明底色的小程序 |
返回参数
| 属性 | 类型 | 说明 |
|---|---|---|
| buffer | buffer | 图片 Buffer |
| errcode | number | 错误码 |
| errmsg | string | 错误信息 |
接口请求成功会返回的图片 Buffer(如果调用成功,会直接返回图片二进制内容(图片文件流),如果请求失败,会返回 JSON 格式的数据。)
请求代码:
注意:这个与前面获取授权凭证的网络请求不同的是因为要接收请求返回过来的图片二进制内容(buffer),然后需要把二进制文件流转化为byte[]二进制字节流,然后在转化Image。
/// <summary>
/// 获取小程序码图片
/// </summary>
/// <param name="access_token">接口调用凭据</param>
/// <param name="param">携带参数</param>
private Image GetWetchatAppletQRCodeImage(string access_token, string param)
{
string requestData = "{\"scene\":\"" + param + "\"}";
string requestUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + access_token;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
byte[] payload = System.Text.Encoding.UTF8.GetBytes(requestData);
request.ContentLength = payload.Length;
Stream writer = request.GetRequestStream();
writer.Write(payload, 0, payload.Length);
writer.Close();
HttpWebResponse response;
response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();//获取返回的图片 Buffer(文件流)
byte[] imageBuffer = StreamToBytes(stream);
return ByteArrayConvertToImage(imageBuffer);
}
/// <summary>
/// 将文件数据流转为二进制byte[]字节流
/// </summary>
/// <param name="stream">文件流</param>
/// <returns></returns>
private byte[] StreamToBytes(Stream stream)
{
List<byte> bytes = new List<byte>();
int temp = stream.ReadByte();
while (temp != -1)
{
bytes.Add((byte)temp);
temp = stream.ReadByte();
}
return bytes.ToArray();
}
/// <summary>
/// byte [] 转化为Iamge
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
public static Image ByteArrayConvertToImage(byte[] buffer)
{
using (MemoryStream ms = new MemoryStream(buffer))
{
// 直接调用Image库类中自带的方法使用MemoryStream实例对象获取Image
return Image.FromStream(ms);
}
}
小程序码和背景图合并
/// <summary>
/// 小程序推广二维码获取
/// </summary>
/// <param name="userId">小程序码携带的用户参数</param>
/// <returns></returns>
public JsonResult GetCompositePictureUrl(int userId)
{
//图片存放物理路径
var savePhysicalPath = HttpContext.Request.MapPath("~/qrcode/");
var imgBack = Image.FromFile(savePhysicalPath + "ewm.jpg");//合成背景图片
var wechatQrcodeImg = GetWetchatAppletQRCodeImage(GetWechatAccessToken(),userId.ToString());//获取小程序码图片
var compositePictureUrl = CompositePicture(imgBack, wechatQrcodeImg, savePhysicalPath, 232, 719, 290, 290);
return Json(new { code = 0, compositePictureUrl = compositePictureUrl });
}
/// <summary>
/// 合成图片
/// </summary>
/// <param name="backgroundImage">背景图</param>
/// <param name="qrCodeImg">二维码图片</param>
/// <param name="savePhysicalPath">图片存放物理路径</param>
/// <param name="xDeviation">绘制图像X轴偏差</param>
/// <param name="yDeviation">绘制图像Y轴偏差</param>
/// <param name="width">绘制图像宽</param>
/// <param name="height">绘制图像高</param>
/// <returns></returns>
public string CompositePicture(Image backgroundImage, Image qrCodeImg, string savePhysicalPath, int xDeviation = 0, int yDeviation = 0, int width = 0, int height = 0)
{
Bitmap bitmap = new Bitmap(backgroundImage.Width, backgroundImage.Height);
Graphics graphics = Graphics.FromImage(bitmap);//绘图
graphics.Clear(Color.White);
SolidBrush surush = new SolidBrush(Color.White);
graphics.DrawImage(backgroundImage, 0, 0, backgroundImage.Width, backgroundImage.Height);
graphics.DrawImage(qrCodeImg, xDeviation, yDeviation, width, height);
GC.Collect();//垃圾清理
string compositePictureUrl = savePhysicalPath + Guid.NewGuid().ToString() + ".jpg";
//合成图片保存
bitmap.Save(compositePictureUrl, System.Drawing.Imaging.ImageFormat.Jpeg);
return compositePictureUrl;
}
合成效果图

DotNetGuide技术社区交流群
- DotNetGuide技术社区是一个面向.NET开发者的开源技术社区,旨在为开发者们提供全面的C#/.NET/.NET Core相关学习资料、技术分享和咨询、项目推荐、招聘资讯和解决问题的平台。
- 在这个社区中,开发者们可以分享自己的技术文章、项目经验、遇到的疑难技术问题以及解决方案,并且还有机会结识志同道合的开发者。
- 我们致力于构建一个积极向上、和谐友善的.NET技术交流平台,为广大.NET开发者带来更多的价值和成长机会。
.NET生成微信小程序推广二维码的更多相关文章
- 关于微信小程序获取二维码的踩坑记录
1.踩坑需求:获取小程序的二维码 2.踩坑接口: https://api.weixin.qq.com/wxa/getwxacode?access_token=ACCESS_TOKEN3 踩坑代码 pu ...
- tp5生成小程序推广二维码
//获取用户经销商信息 及生成推广二维码 public function qrcode() { //拿到openid 查找用户表内是否有该用户 没有则拒绝生成二维码 有则查看是否已生成二维码 有生成则 ...
- 微信小程序获取二维码(直接上代码)https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=ACCESS_TOKEN
应为是直接返回二进制数据所有与其他接口些许差别,希望能帮助现在的你! 谢谢!!! /** * 37.微信二维码生成 */ public String getWeiXinCourseMap() { ...
- 微信小程序--扫描二维码
场景---在微信中扫描朋友发来的二维码后进入小程序,其实那个地址是带有参数的,那么如何接收那个参数呢,其实就是进入小程序页面的onLoad生命周期行数的options参数里面.
- 又是新动作!微信小程序专属二维码出炉
又到了晚上,微信又给我们带来了惊喜,并这次不是新的能力,而是把大家再熟悉不过的二维码换了新的造型. 正式揭晓:微信特制的小程序码.扫一扫新二维码 只要你的微信升级到了 6.5.7 版本,就可以扫码或者 ...
- 微信小程序获取二维码并把logo替换为自己的头像
$avatarUrl = 'http://cms-bucket.nosdn.127.net/2018/05/28/a1a44ffdc2d24f928c1860d4fbf54703.jpeg?image ...
- 微信小程序通过二维码获取参数运行
小程序开发过程中会遇到参数id会通过二维码获取,然后执行接口获取数据,但是难免会遇到带过来的参数出现乱码,这样就需要解码,多个参数时就需要进行处理取我们需要的字段值:小程序开发过程中会遇到参数id会通 ...
- 微信小程序获取二维码API
<%@ WebHandler Language="C#" Class="ce" %> using System; using System.Web; ...
- 微信小程序获取二维码参数
var scene = decodeURIComponent(options.scene)
- 用 Python 把微信小程序的二维码转化成图片
官方文档 import cString import requests from tornado.web import authenticated, RequestHandler URL = 'htt ...
随机推荐
- 日志监控平台搭建(Loki+promtail+grafana)
搭建Loki+promtail+grafana日志监控平台,可以直接在grafana的UI界面查看系统应用日志,使日志查看起来更方便.快捷. Loki:主服务器,负责存储日志和处理查询. Prom ...
- Git-更换服务器问题
一.Permission denied (publickey) git指令出现Permission denied (publickey),是ssh key过期的问题,需要对ssh key进行更新,所有 ...
- 【译】通过 GitHub Copilot Chat 简化代码优化和调试(AI 辅助编程)
今年3月,我们宣布了 Visual Studio 2022 的 GitHub Copilot Chat.通过 Chat, Copilot 已经超越了代码补全,提供了对代码工作原理的深入分析和解释.它支 ...
- java与es8实战之三:Java API Client有关的知识点串讲
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<java与es8实战>系 ...
- Python字符串操作函数split()和join()
字符串拆分 在python中有切片(Slice)操作符,可以对字符串进行截取,还提供了split()函数可以将一个 字符串分裂成多个字符串组成的列表.在使用split()函数来拆分字符串之前,我们先来 ...
- 浅谈基于QT的截图工具的设计与实现
本人一直在做属于自己的一款跨平台的截图软件(w4ngzhen/capi(github.com)),在软件编写的过程中有一些心得体会,所以有了本文.其实这篇文章酝酿了很久,现在这款软件有了雏形,也有空梳 ...
- ipmitool配置机器的BMC
一.设置IP地址 1.确定操作对象 #ipmitool mc info 输出中"Device Revision"是命令的操作对象 2.设置BMC IP # ipmitool -I ...
- React仿大众点评外卖app
主要使用技术: react react-router4 redux: action.reducer.store管理数据 fetch: 进行数据交互 prismjs : 页面嵌入代码,高亮显示插件 bu ...
- Spring中事务的传播行为有哪些?
Spring中事务的传播行为有哪些? 现在我们来谈一个场景,再来引出事务传播行为这个概念.现在有methodA( ) 和 methodB( ),而且两个方法都显示的开启了事务,那么methodB( ) ...
- 基于百度AI实现文字和图像敏感内容审核
前言 百度AI是指百度公司的人工智能技术全称.它采用深度学习技术,包括自然语言处理.语音识别.计算机视觉.知识图谱等,可应用于各个领域如互联网.医疗.金融.教育.汽车.物流等.百度AI的发展将帮助人类 ...