前言

以前h5网页在微信里打开,右上角分享到微信好友或者朋友圈 是微信自己抓取的首图 现在 好像不行了。这是因为微信更新了API,必须自行配置,接入jssdk,才能实现自定义分享信息的功能。详细可以查看微信官方开发者文档,地址:

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

JS接口安全域名

接入jssdk时,就需要配置JS接口安全域名,因此需要登录微信公众平台,在公众号设置→功能设置中,填写JS接口安全域名,域名即为H5项目的域名(如:www.baidu.com),同时需要下载一个txt验证文件,并放置到服务器的根路径下,实际操作时根据提示即可。

1.png

设置白名单

这一步其实应该放到后面获取access_token步骤中,我这里正好已经登录在公众号平台,所以就一并操作了。后面讲到获取access_token和jsapi_ticket时,需要访问服务器,因此需要将H5项目服务器的IP地址添加到白名单中,否则接口将无法调用成功。具体设置方法:在开发→基本设置→IP白名单中进行添加相应的IP地址即可。如下图所示

2.png

获取access_token

access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。详细说明详见官当开发文档:

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183

首先需要在H5页面内中引入js文件

<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

具体获取的代码如下:

$.ajax({
  url: "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=AppSecret";,  //接口地址
  type: "Get",
  dataType: 'jsonp',
  crossDomain: true,//与上一项解决跨域问题
  success: function (data) {
   //将access_token缓存起来
   localStorage.setItem("access_token", data.access_token);
  }
});

其中参数appid和secret均可以在公众号后台查看获取。

获取jsapi_ticket

jsapi_ticket是公众号用于调用js接口的临时票据。有效期7200秒,跟公众号普通access_token一样,必须全局缓存起来,因为这个ticket获取次数有限,超过次数将无法使用。获取jsapi_ticket也是为了后面生成signature签名做准备。具体方法与access_token类似,替换访问接口即可。

$.ajax({
 url: "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi",  //接口地址
 type: "Get",
 dataType: 'jsonp',
 crossDomain: true,
 success: function (data) {
   //缓存jsapi_ticket
   localStorage.setItem("jsapi_ticket", ticket);
 }
});

生成signature,并自定义分享信息

前台的代码实现:

var url = location.href.split('#')[0];  //分享的文章地址
var requestUrl = "/app/getticket?ticket=" + ticket + "&url=" + url;
$.ajax({
	url: requestUrl,
	type: "Get",
	dataType: 'json',
	success: function (data) {
		var appId = data.appId;
		var timestamp = data.timestamp;
		var nonceStr = data.noncestr;
		var signature = data.signature;
		wx.config({
			debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,
						  // 若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
			appId: appId + '', // 必填,公众号的唯一标识
			timestamp: timestamp + '', // 必填,生成签名的时间戳
			nonceStr: nonceStr + '', // 必填,生成签名的随机串
			signature: signature + '',// 必填,签名,见附录1
			jsApiList: ["onMenuShareTimeline", "onMenuShareAppMessage", "onMenuShareQQ"] 
			// 必填,需要使用的JS接口列表,所有JS接口列表见附录2
		});

		wx.ready(function () {
			var imgurl = '缩略图完整地址';
			var title = '自定义标题';
			var desc = '自定义描述信息';
			wx.onMenuShareTimeline({
				title: title, // 分享标题
				desc: desc, // 分享描述
				link: url, // 分享链接
				imgUrl: imgurl, // 分享图标
				success: function () {
					// 用户确认分享后执行的回调函数
				},
				cancel: function () {
					// 用户取消分享后执行的回调函数
				}
			});

			wx.onMenuShareAppMessage({
				title: title, // 分享标题
				desc: desc, // 分享描述
				link: url, // 分享链接
				imgUrl: imgurl, // 分享图标
				type: '', // 分享类型,music、video或link,不填默认为link
				dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
				success: function () {
					// 用户确认分享后执行的回调函数
				},
				cancel: function () {
					// 用户取消分享后执行的回调函数
				}
			});

			wx.onMenuShareQQ({
				title: title, // 分享标题
				desc: desc, // 分享描述
				link: url, // 分享链接
				imgUrl: imgurl, // 分享图标
				success: function () {
					// 用户确认分享后执行的回调函数
				},
				cancel: function () {
					// 用户取消分享后执行的回调函数
				}
			});
		});
	}
});

后台生成签名的逻辑代码:

/// <summary>
///  根据传入的jsapi_ticket生成signature签名
/// </summary>
/// <param name="ticket"></param>
/// <returns></returns>
public JsonResult GetTicket(string ticket, string url)
{
    SignatureTicket model = new SignatureTicket();
    model.appId = CommonSharp.appId;
    model.noncestr = CommonSharp.GetRnd(16, true, true, true, false, "");
    model.timestamp = CommonSharp.GetTimeStamp();
    string _url = System.Web.HttpUtility.UrlDecode(url);
    string string1 = "jsapi_ticket=" + ticket + "&noncestr=" + model.noncestr + "&timestamp=" + model.timestamp + "&url=" + url;
    model.signature = CommonSharp.GetPwd(string1);
    return Json(model);
}

其中GetPwd方法的逻辑如下:

public static string GetPwd(string str)
{
    byte[] cleanBytes = Encoding.Default.GetBytes(str);
    byte[] hashedBytes = System.Security.Cryptography.SHA1.Create().ComputeHash(cleanBytes);
    return BitConverter.ToString(hashedBytes).Replace("-", "");
}

至此,需要配置的以及后台代码均已完毕,发布后放到服务器上进行测试使用。


---------------------------------- 完美的分割线 ---------------------------------------

根据上面的方式,开始确实可以实现想要的功能,但晚上下班回家了,无意中再次打开时发现又不行了,在电脑上查看时,报了如下错误:

invalid credential, access_token is invalid or not latest hint

一番折腾之后发现,是由于access_token过期了,导致生成的签名失败。分析上面的代码,发现将获取到的access_token缓存到localstorage的逻辑是有问题的,获取到的access_token默认有效期为2小时,如果重新请求API接口,新的access_token会覆盖原来的值,而我将access_token存入localstorage后,其实并没有做进一步的有效期的校验和定时刷新,所以过了有效期之后,自然就会出现上面的那个错误了。

知道了原因,那就开始动手修改吧。当在前端利用jsonp访问微信API接口时,莫名其妙的又出现了另一个错误:

Uncaught SyntaxError: Unexpected token :

这个应该是跟ajax跨域请求返回的数据格式有关系,但是试了很多方法都不行,无奈,只好换一种思路,打算不再从前端获取access_token了,改从后端去获取,这样就可以避免了ajax访问时跨域的问题。还是直接上代码吧~~

后台C#代码实现如下:

/// <summary>
///  获取access_token
/// </summary>
/// <returns></returns>
public JsonResult GetAccessToken()
{
  AccessToken result = new AccessToken();
  if (HttpRuntime.Cache == null)
  {
    result = GetToken();
  }
  var accessTokenCache = HttpRuntime.Cache.Get(CommonSharp.token_cahekey);
  if (accessTokenCache != null)
  {
    result.Token = accessTokenCache.ToString();
  }
  else
  {
    result = GetToken();
  }
  return Json(result);
}
private AccessToken GetToken()
{
    AccessToken result = new AccessToken();
    var client = new WebClient();
    client.Encoding = System.Text.Encoding.UTF8;
    var responseData = client.DownloadString(string.Format(@"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential
        &appid={0}&secret={1}", CommonSharp.appId, CommonSharp.app_secret));
    var serializer = new JavaScriptSerializer();
    var accessDictionary = serializer.Deserialize<Dictionary<string, object>>(responseData);
    var accessToken = accessDictionary[CommonSharp.token_cahekey];
    if (accessToken != null)
    {
        HttpRuntime.Cache.Insert(CommonSharp.token_cahekey, accessToken, null, DateTime.Now.AddSeconds(7100), 
            TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Normal, null);
        result.Token = accessToken.ToString();
    }
    return result;
}

总结

功能算是完成了,但是在做的过程中,也出现了不少的问题,比如在生成签名时,在电脑上看不出来,在手机上访问时,就会总提示 “config:invalid signature”,需要注意的是,在生成签名时,url需要从前台传到后台去,同时不能对此url地址进行编码、转义等操作,而且要去掉地址中#部分,正确使用:location.href.split('#')[0]。

参考文档:

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

https://bbs.csdn.net/topics/392288522

https://bbs.csdn.net/topics/392210227?list=lz

https://www.cnblogs.com/lanxiaoke/p/6413082.html

作者: 一蓑烟雨

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

分类: Html5系列
posted 阅读(277 ) 评论(0 )

评论内容: