很多时候我们要在微信中分享h5网页,这个时候就得用微信的分享接口来自定义分享的地址、标题、描述、缩略图了。

分享到微信的时候遇到一个问题,就是第一次分享到微信里,是正确的,但是在微信打开分享的链接,再次分享的时候,发现小图片没了。

原因就是微信在你分享的时候,会自动给你分享的地址后面加入参数,导致你分享的地址改变了,这时候再去用原来的地址获取签名,就不能用了。

解决方法,动态获取地址:

var link = encodeURIComponent(location.href.split('#')[0]);//编码动态获取地址

var link = location.href.split('#')[0];//动态获取地址

代码:

 <script src="js/jquery.min.js"></script>
    <script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
    <script src="js/sha1.js"></script>
    <script src="js/WeiXinShare.js"></script>
    <script type="text/javascript">
        //var link = "http://adv.xxx.com/Index.html";//原网页地址
        //var link = encodeURIComponent(location.href.split('#')[0]);//编码动态获取地址
        //var link = "http://adv.xxx.com/Index.html?from=groupmessage";//微信加入参数后的地址
        var link = location.href.split('#')[0];//动态获取当前地址,防止微信在原地址后加入参数

        var imgUrl = "http://adv.xxx.com/img/fm.png";//缩略图地址
        var apiUrl = "https://api.xxx.com/Common/GetSignature";//服务器端签名
        var title = "这里是分享标题";
        var desc = "这里是分享描述";
        Share(link, imgUrl, title, desc, apiUrl);
    </script>

Share函数代码:

function Share(link, imgUrl, title, desc, apiUrl) {
    var randNum = Math.floor(Math.random(1000, 9999) * 10000);
    $.ajax({
        url: apiUrl,
        type: 'GET',
        dataType: 'jsonp',
        async: false,
        data:
        {
            linkUrl: link,
            randNum: randNum
        }
    }).done(function (d) {
        //debugger;
        ShareCallBack(d, link, imgUrl, title, desc);
    }).fail(function () {
        console.log("error");
    }).always(function () {
    });
}

function ShareCallBack(d, link, imgUrl, title, desc) {
    //debugger;
    var appid = "";
    var timestamp = "";
    var noncestr = "";
    var signature = "";
    if (d.Data != undefined && d.Data != null) {

        var result = $.parseJSON(d.Data);
        timestamp = result.timestamp;
        noncestr = result.noncestr;
        signature = result.signature;
        appid = result.appid;

        //weixin begin
        wx.config({
            debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: appid, // 必填,公众号的唯一标识
            timestamp: timestamp, // 必填,生成签名的时间戳
            nonceStr: noncestr, // 必填,生成签名的随机串
            signature: signature, // 必填,签名,见附录1
            jsApiList: ["onMenuShareTimeline", "onMenuShareAppMessage", "onMenuShareQQ", "onMenuShareWeibo", "onMenuShareQZone"]
            //jsApiList 必填,需要使用的JS接口列表,所有JS接口列表见附录2
        });

        wx.ready(function () {
            //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口
            // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
            wx.onMenuShareTimeline({
                title: title, // 分享标题
                desc: desc, // 分享描述
                link: link, // 分享链接
                imgUrl: imgUrl, // 分享图标
                success: function () {
                    // 用户确认分享后执行的回调函数
                },
                cancel: function () {
                    // 用户取消分享后执行的回调函数
                }
            });

            //获取“分享给朋友”按钮点击状态及自定义分享内容接口
            wx.onMenuShareAppMessage({
                title: title, // 分享标题
                desc: desc, // 分享描述
                link: link, // 分享链接
                imgUrl: imgUrl, // 分享图标
                type: 'link', // 分享类型,music、video或link,不填默认为link
                dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
                success: function () {
                    // 用户确认分享后执行的回调函数
                },
                cancel: function () {
                    // 用户取消分享后执行的回调函数
                }
            });

            //获取“分享到QQ”按钮点击状态及自定义分享内容接口
            wx.onMenuShareQQ({
                title: title, // 分享标题
                desc: desc, // 分享描述
                link: link, // 分享链接
                imgUrl: imgUrl, // 分享图标
                success: function () {
                    // 用户确认分享后执行的回调函数
                },
                cancel: function () {
                    // 用户取消分享后执行的回调函数
                }
            });
            //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口
            wx.onMenuShareWeibo({
                title: title, // 分享标题
                desc: desc, // 分享描述
                link: link, // 分享链接
                imgUrl: imgUrl, // 分享图标
                success: function () {
                    // 用户确认分享后执行的回调函数
                },
                cancel: function () {
                    // 用户取消分享后执行的回调函数
                }
            });
            //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口
            wx.onMenuShareQZone({
                title: title, // 分享标题
                desc: desc, // 分享描述
                link: link, // 分享链接
                imgUrl: imgUrl, // 分享图标
                success: function () {
                    // 用户确认分享后执行的回调函数
                },
                cancel: function () {
                    // 用户取消分享后执行的回调函数
                }
            });

            wx.error(function (res) {

                // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
            });

        });
        //weixin end
    }
}

服务器端签名:

/// <summary>
        /// 获取微信 signature
        /// </summary>
        /// <param name="callback"></param>
        [AcceptVerbs("GET")]
        public void GetSignature(string callback, string linkUrl)
        {
            MessagesDataCodeModel json = new MessagesDataCodeModel(false, "无效参数", 401);
            try
            {
                string AppId = "xxxxxxxx";//微信公众号官网签发的 appid和appsecret
                string AppSecret = "xxxxxxx";
                DateTime endDate = DateTime.Now.AddSeconds(7200);
                string token = "", ticket = "";
                List<Models.WeiXinTokens> list = WeiXinTokensBLL.GetList();
                if (list != null && list.Count > 0)
                {
                    if (list[0].EndDate > DateTime.Now)
                    {
                        token = list[0].Token.Trim();
                        ticket = list[0].Ticket.Trim();
                    }
                }

                if (string.IsNullOrEmpty(token))
                {
                    string result = Common.WeiXinHelper.GetJsApiTicket(AppId, AppSecret);
                    JavaScriptSerializer jss = new JavaScriptSerializer();
                    WeiXinTokenModel model = jss.Deserialize<WeiXinTokenModel>(result);
                    if (model != null)
                    {
                        Models.WeiXinTokens wxt = new Models.WeiXinTokens();
                        wxt.Token = model.token;
                        wxt.Ticket = model.ticket;
                        wxt.EndDate = endDate;
                        if (list.Count > 0)
                        {
                            wxt.ID = list[0].ID;
                            WeiXinTokensBLL.ModifyEntity(wxt);
                        }
                        else
                        {
                            WeiXinTokensBLL.Append(wxt);
                        }

                        token = model.token;
                        ticket = model.ticket;
                    }
                }
                else
                {
                    Models.WeiXinTokens wxt = list[0];
                    wxt.Token = token;
                    wxt.Ticket = ticket;
                    WeiXinTokensBLL.ModifyEntity(wxt);
                }

                string noncestr = Guid.NewGuid().ToString().Replace("-", "");
                int timestamp = Utils.ConvertDateTimeInt(DateTime.Now);
                string key_str = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + linkUrl;
                string signature = Utils.EncryptToSHA1(key_str);                
                string jsonStr = "{\"ticket\":\"" + ticket + "\",\"token\":\"" + token + "\",\"noncestr\":\"" + noncestr + "\",\"timestamp\":\"" + timestamp + "\",\"appid\":\"" + AppId + "\",\"signature\":\"" + signature + "\",\"url\":\"" + linkUrl + "\"}";
                json.Success = true;
                json.Msg = "操作成功";
                json.Code = 200;
                json.Data = jsonStr;
            }
            catch (Exception ex)
            {
                json.Success = false;
                json.Msg = "服务器无响应";
                json.Code = 500;
                json.Data = -1;
            }

            string str = ToJsonTran.ToJson2(json);
            if (!string.IsNullOrEmpty(callback))
            {
                str = callback + "(" + str + ")";
            }
            System.Web.HttpContext.Current.Response.Clear();
            System.Web.HttpContext.Current.Response.Write(str);
            System.Web.HttpContext.Current.Response.End();
        }

辅助方法:

/// <summary>
        /// C# SHA1散列算法
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string EncryptToSHA1(string str)
        {
            byte[] cleanBytes = Encoding.Default.GetBytes(str);
            byte[] hashedBytes = System.Security.Cryptography.SHA1.Create().ComputeHash(cleanBytes);
            return BitConverter.ToString(hashedBytes).Replace("-", "");
        }
/// <summary>  
        /// DateTime时间格式转换为Unix时间戳格式  
        /// </summary>  
        /// <param name="time"> DateTime时间格式</param>  
        /// <returns>Unix时间戳格式</returns>  
        public static int ConvertDateTimeInt(System.DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (int)(time - startTime).TotalSeconds;
        }

签名程序:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;

namespace Common
{
    public class WeiXinHelper
    {
        public static string GetJsApiTicket(string AppId, string AppSecret)
        {
            JavaScriptSerializer jss = new JavaScriptSerializer();
            string result_token = GetAccessToken(AppId, AppSecret);
            string result_jsapi_ticket = "";
            if (!string.IsNullOrEmpty(result_token))
            {
                result_jsapi_ticket = GetJsApiTicketByToken(result_token);
            }
            return "{\"token\":\"" + result_token + "\",\"ticket\":\"" + result_jsapi_ticket + "\"}";
        }

        /// <summary>
        /// 获得微信AccessToken
        /// 正常返回:{"access_token":"ACCESS_TOKEN","expires_in":7200}
        /// 错误返回:{"errcode":40013,"errmsg":"invalid appid"}
        /// </summary>
        /// <param name="AppId"></param>
        /// <param name="AppSecret"></param>
        /// <returns></returns>
        public static string GetAccessToken(string AppId, string AppSecret)
        {
            string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + AppId + "&secret=" + AppSecret;
            string result_token = "";
            WebRequest webRequest = System.Net.HttpWebRequest.Create(url);
            WebResponse webResponse = webRequest.GetResponse();
            Stream stream = webResponse.GetResponseStream();
            using (StreamReader sr = new StreamReader(stream))
            {
                result_token = sr.ReadToEnd();
            }

            JavaScriptSerializer jss = new JavaScriptSerializer();
            WeiXinAccessTokenResult atr = jss.Deserialize<WeiXinAccessTokenResult>(result_token);
            if (!string.IsNullOrEmpty(atr.access_token))
            {
                return atr.access_token;
            }
            return "";
        }

        public static string GetJsApiTicketByToken(string AccessToken)
        {
            string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + AccessToken + "&type=jsapi";
            string result = Utils.ClientRequest(url, "", "GET");
            JavaScriptSerializer jss = new JavaScriptSerializer();
            WeiXinJsApiTicketResult ticket_model = jss.Deserialize<WeiXinJsApiTicketResult>(result);
            if (ticket_model.errcode == "0")
            {
                return ticket_model.ticket;
            }
            return "";
        }
    }
    public class WeiXinJsApiTicketResult
    {
        public string errcode { get; set; }
        public string errmsg { get; set; }
        public string ticket { get; set; }
        public string expires_in { get; set; }
    }
    public class WeiXinAccessTokenResult
    {
        //正常返回:{"access_token":"ACCESS_TOKEN","expires_in":7200}
        //错误返回:{"errcode":40013,"errmsg":"invalid appid"}
        public string access_token { get; set; }
        public string expires_in { get; set; }
        public string errcode { get; set; }
        public string errmsg { get; set; }
        public string error { get; set; }
    }
}

 

 微信分享SDK:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

posted on 2017-11-29 13:20  邢帅杰  阅读(7624)  评论(0编辑  收藏  举报