要实现微信分享网页时自定义缩略图和简介,需开发者在公众平台网站中创建公众号、获取接口权限后,通过微信JS-SDK的分享接口,来实现微信分享功能。
下面来说明实现步骤。
第一部分 准备步骤
步骤一:注册微信公众号。
申请公众号网址
步骤二:认证微信公众号。
通过左侧导航“设置”--“微信认证”进入。不进行认证,无法使用微信JS-SDK分享接口。详见接口权限说明文档。
开通微信认证需准备如下图所示材料,具体认证流程详见微信认证申请流程(企业类型)文档。
步骤三:设置IP白名单。获取AppID和AppSecret。
通过左侧导航“开发”--“基本配置”进入。通过开发者ID及密码调用获取access_token接口时,需要设置访问来源IP为白名单。可将服务器ip、开发机ip、测试机ip都进行设置。
步骤四:配置JS接口安全域名。
通过左侧导航“设置”--“公众号设置”--“功能设置”进入。设置JS接口安全域名后,公众号开发者才可在该域名下调用微信开放的JS接口。具体设置步骤如下图所示。
步骤五:填写服务器配置。(可选)
通过左侧导航“开发”--“基本配置”进入。仅仅是为了实现分享功能的话,不是必填项,但为了实现其他功能(如回复消息),需进行配置。服务器配置是为了正确响应微信发送的Token验证等信息。详见入门指引文档中“1.4开发者基本配置”部分。
第二部分 开发步骤
步骤1:通过公众号里的AppID和AppSecret获取access_token(接口调用凭据),并进行缓存(有效期为2小时)
公众平台以access_token为接口调用凭据,来调用接口,所有接口的调用需要先获取access_token,access_token在2小时内有效,过期需要重新获取,但1天内获取次数有限,开发者需自行存储,详见获取接口调用凭据(access_token)文档。
public static string GetAccess_token() { string access_token = string.Empty; //从缓存获取 string cacheName = "Weixin_access_token"; object obj = CacheHelper.GetCache(cacheName); if (obj != null) { access_token = obj.ToString(); } //从接口获取 else { string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + AppID + "&secret=" + AppSecret; access_token = SubmitHttpWebRequest(url, "access_token"); //设置缓存 //7200秒内有效,不可无限次调取微信接口 CacheHelper.SetCache(cacheName, access_token, 7200); } return access_token; }
步骤2:获取jsapi_ticket,并进行缓存(有效期为2小时)。jsapi_ticket是公众号用于调用微信JS接口的临时票据
public static string GetJsapi_Ticket() { string jsapi_ticket = string.Empty; //从缓存获取 string cacheName = "Weixin_jsapi_ticket"; object obj = CacheHelper.GetCache(cacheName); if (obj != null) { jsapi_ticket = obj.ToString(); } //从接口获取 else { string access_token = GetAccess_token(); string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=" + access_token; jsapi_ticket = SubmitHttpWebRequest(url, "ticket"); //设置缓存 //7200秒内有效,不可无限次调取微信接口 CacheHelper.SetCache(cacheName, jsapi_ticket, 7200); } return jsapi_ticket; }
步骤3:生成JS-SDK权限验证的签名信息,并通过接口调用
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
public static string[] GetSignature(string url) { //JSAPI调用凭证 string jsapi_ticket = GetJsapi_Ticket(); //随机生成的字符串 string noncestr = CreateRandCode(); //当前时间戳 TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0); string timestamp = ((Int64)ts.TotalSeconds).ToString(); //string timestamp = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();//.net framework4.6 //url if (url.IndexOf("#") > 0) { url = url.Substring(0, url.IndexOf("#")); } //签名 StringBuilder string1 = new StringBuilder(); string1.AppendFormat("jsapi_ticket={0}&noncestr={1}×tamp={2}&url={3}", jsapi_ticket, noncestr, timestamp, url); string signature = GetSHA1(string1.ToString()); //返回相关信息 string[] rtn = new string[] { AppID, noncestr, timestamp, signature }; return rtn; }
通过接口调用(公众平台接口调用仅支持80端口。)
public class WeixinController : ApiController { ////// 获取签名信息 /// /// /// [HttpGet] [AllowAnonymous] public WeixinSignatureConfig GetSignature(string url) { //微信配置 string[] weixin = Tencent.WeixinConfig.GetSignature(url); WeixinSignatureConfig weixinConfig = new WeixinSignatureConfig { appId = weixin[0], nonceStr = weixin[1], timestamp = weixin[2], signature = weixin[3] }; return weixinConfig; } }
相关方法:
提交网络请求 SubmitHttpWebRequest(string url, string para = "")
private static string SubmitHttpWebRequest(string url, string para = "") { string retString = string.Empty; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "GET"; request.ContentType = "application/json"; request.Timeout = 10000; try { HttpWebResponse response = (HttpWebResponse)request.GetResponse(); string encoding = response.ContentEncoding; if (encoding == null || encoding.Length < 1) { encoding = "UTF-8"; //默认编码 } using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding))) { retString = reader.ReadToEnd(); if (para != "") { JObject jsonObj = (JObject)JsonConvert.DeserializeObject(retString); if (jsonObj[para] != null) { retString = jsonObj[para].ToString(); } } } } catch (WebException ex) { retString = null; } return retString; }
生成随机字符串CreateRandCode(int codeLen = 16)
public static string CreateRandCode(int codeLen = 16) { string codeSerial = "2,3,4,5,6,7,a,c,d,e,f,h,i,j,k,m,n,p,r,s,t,A,C,D,E,F,G,H,J,K,M,N,P,Q,R,S,U,V,W,X,Y,Z"; if (codeLen == 0) { codeLen = 16; } string[] arr = codeSerial.Split(','); string code = ""; int randValue = -1; Random rand = new Random(unchecked((int)DateTime.Now.Ticks)); for (int i = 0; i < codeLen; i++) { randValue = rand.Next(0, arr.Length - 1); code += arr[randValue]; } return code; }
SHA1加密GetSHA1(string string1)
private static string GetSHA1(string string1) { SHA1 sha; ASCIIEncoding enc; string hash = ""; sha = new SHA1CryptoServiceProvider(); enc = new ASCIIEncoding(); byte[] dataToHash = enc.GetBytes(string1); byte[] dataHashed = sha.ComputeHash(dataToHash); hash = BitConverter.ToString(dataHashed).Replace("-", ""); hash = hash.ToLower(); return hash; }
缓存设置CacheHelper.cs
using System; using System.Collections; using System.Web; using System.Web.Caching; namespace WeixinShare { ////// Caching 的摘要说明 /// public class CacheHelper { /// /// 获取当前应用程序指定CacheKey的Cache值 /// /// /// y public static object GetCache(string CacheKey) { System.Web.Caching.Cache objCache = HttpRuntime.Cache; return objCache[CacheKey]; } /// /// 设置当前应用程序指定CacheKey的Cache值 /// /// /// public static void SetCache(string CacheKey, object objObject) { System.Web.Caching.Cache objCache = HttpRuntime.Cache; objCache.Insert(CacheKey, objObject); } /// /// 设置当前应用程序指定CacheKey的Cache值 /// /// /// public static void SetCache(string CacheKey, object objObject, DateTime absoluteExpiration, TimeSpan slidingExpiration) { System.Web.Caching.Cache objCache = HttpRuntime.Cache; objCache.Insert(CacheKey, objObject, null, absoluteExpiration, slidingExpiration); } /// /// 设置数据缓存 /// public static void SetCache(string CacheKey, object objObject, int timeout = 7200) { try { if (objObject == null) return; var objCache = HttpRuntime.Cache; //相对过期 //objCache.Insert(cacheKey, objObject, null, DateTime.MaxValue, timeout, CacheItemPriority.NotRemovable, null); //绝对过期时间 objCache.Insert(CacheKey, objObject, null, DateTime.Now.AddSeconds(timeout), TimeSpan.Zero, CacheItemPriority.High, null); } catch (Exception) { //throw; } } /// /// 清除单一键缓存 /// /// public static void RemoveKeyCache(string CacheKey) { try { System.Web.Caching.Cache objCache = HttpRuntime.Cache; objCache.Remove(CacheKey); } catch { } } ///// ///// 清除所有缓存 ///// //public static void RemoveAllCache() //{ // System.Web.Caching.Cache _cache = HttpRuntime.Cache; // IDictionaryEnumerator CacheEnum = _cache.GetEnumerator(); // if (_cache.Count > 0) // { // ArrayList al = new ArrayList(); // while (CacheEnum.MoveNext()) // { // al.Add(CacheEnum.Key); // } // foreach (string key in al) // { // _cache.Remove(key); // } // } //} /// /// 清除所有缓存 /// public static void RemoveAllCache() { var cache = HttpRuntime.Cache; var cacheEnum = cache.GetEnumerator(); while (cacheEnum.MoveNext()) { cache.Remove(cacheEnum.Key.ToString()); } } /// /// 以列表形式返回已存在的所有缓存 /// /// public static ArrayList ShowAllCache() { ArrayList al = new ArrayList(); System.Web.Caching.Cache _cache = HttpRuntime.Cache; if (_cache.Count > 0) { IDictionaryEnumerator CacheEnum = _cache.GetEnumerator(); while (CacheEnum.MoveNext()) { al.Add(CacheEnum.Key); } } return al; } } }
Models,WeixinSignatureConfig
namespace WeixinShare.Models { public class WeixinSignatureConfig { public string appId { get; set; } public string nonceStr { get; set; } public string timestamp { get; set; } public string signature { get; set; } } }
步骤4:网页前端调用微信JSSDK
微信JS-SDK是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包。
通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。
@*微信分享接口*@
方法封装:WeixinShare.js
function WeixinShare(title, desc, link, imgUrl, jsApiList) { $(document).ready(function () { //分享链接处理 if (link.indexOf("#") > 0) { link = link.substring(0, link.indexOf("#")); } //通过Ajax获取签名信息,不影响主页面的加载逻辑 $.ajax({ url: "/apiaction/Weixin/GetSignature", data: "url=" + encodeURIComponent(link), type: "GET", dataType: "json", success: function (data) { //注入配置信息 wx.config({ debug: false,// 开启调试模式,调用的所有api的返回值会在客户端alert出来 appId: data.appId,// 必填,公众号的唯一标识 timestamp: parseInt(data.timestamp),// 必填,生成签名的时间戳 nonceStr: data.nonceStr,// 必填,生成签名的随机串 signature: data.signature,// 必填,签名 jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData']// 必填,需要使用的JS接口列表 }); //config验证成功后调用微信接口 wx.ready(function () { //分享给朋友 wx.updateAppMessageShareData({ title: title, desc: desc, link: link, imgUrl: imgUrl, success: function () { } }); //分享到朋友圈 wx.updateTimelineShareData({ title: title, desc: desc, link: link, imgUrl: imgUrl, success: function () { } }); }); wx.error(function (res) { console.log(res); }); } }); }); }
完整代码下载:
https://github.com/coolxiaoyi/WeixinShare-JSSDK
总结:
虽然是很简单的一个分享功能,但是步骤较多,涉及到公众号注册、认证、ip配置、域名配置,和获取凭证access_token、jsapi_ticket、SHA1加密算法、config验证等,再加上微信开发文档不够明了,所以大家在开发时会有各种困扰。现在将实现步骤整理出来,希望这篇文章能帮助到大家!