微信朋友圈转发第三方网站带缩略图实现

Posted 潇十一郎

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信朋友圈转发第三方网站带缩略图实现相关的知识,希望对你有一定的参考价值。

前情提要

有时候我们会在朋友圈看到如下两种转发情况:一种是前面带缩略图的 ,一种是无缩略图的,当然有缩略图的不管是从用户体验,还是网站推广运营方都是更优的选择。

那我们看看微信分享朋友圈缩略图是 怎么一回事呢

注:微信6.5.5版本后,微信调整了分享规则。以前的没有通过认证公众号jssdk注入分享的都不是官方认可的分享。

必要前提:① 所打开的分享网页 域名必须经过备案(备案过的二级域名也行) ②公众号后台基本配置里面获取AppID和AppSecret 以添加服务器IP到白名单 显示如下:

 

 代码实现

 在html的Body下 加入如下代码:

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    <script>
                var dataForWeixin = {
                    appId: \'@ViewBag.appid\',
                    url: \'@ViewBag.url\',
                    jsapiTicket:\'@ViewBag.jsapiTicket\',
                    title: \'转发标题\',
                    imgUrl: \'服务器上需要显示的图片路径\',
                    timestamp: \'@ViewBag.timestamp\',
                    nonceStr: \'@ViewBag.nonceStr\',
                    signature: \'@ViewBag.signature\',
                    jsApiList: [\'onMenuShareTimeline\',\'onMenuShareAppMessage\'],
                    callback: function () { }
                };
              wx.config({
                  debug: false,
                  appId: dataForWeixin.appId,
                  timestamp: dataForWeixin.timestamp,
                  nonceStr: dataForWeixin.nonceStr,
                  signature: dataForWeixin.signature,
                  jsApiList: dataForWeixin.jsApiList
              });
    </script>
    <div style="height:0px;overflow:hidden;">
        <img src="服务器上需要显示的图片路径" />
    </div>

在控制器中加入一个 获取微信分享接口的参数如下(再程序入口调用此方法即可)

     /// <summary>
        /// 获取微信分享接口参数
        /// </summary>
        public void GetWX()
        {

            string app_id = ConfigHelper.AppId;
            string AppSecret = ConfigHelper.AppSecret;
            writeLog.WriteLogs("app_id,AppSecret:" + app_id + AppSecret + "");
            Wx_helper jssdk = new Wx_helper(app_id, AppSecret);
            Hashtable ht = jssdk.getSignPackage();
            // 遍历哈希表
            foreach (DictionaryEntry de in ht)
            {
                if (de.Key.ToString() == "appId")
                {
                    ViewBag.appid = de.Value.ToString();
                }
                if (de.Key.ToString() == "nonceStr")
                {
                    ViewBag.nonceStr = de.Value.ToString();
                }
                if (de.Key.ToString() == "timestamp")
                {
                    ViewBag.timestamp = de.Value.ToString();
                }
                if (de.Key.ToString() == "url")
                {
                    ViewBag.url = de.Value.ToString();
                }
                if (de.Key.ToString() == "signature")
                {
                    ViewBag.signature = de.Value.ToString();
                }
                if (de.Key.ToString() == "jsapiTicket")
                {
                    ViewBag.jsapiTicket = de.Value.ToString();
                }
            }
        }

上述代码中 Wx_helper(微信接口类)如下:

    /// <summary>
    /// 微信接口类
    /// </summary>
    public class Wx_helper : DBBase
    {
        private string appId;
        private string appSecret;
        private DataTable DT;

        public Wx_helper(string appId, string appSecret)
        {
            this.appId = appId;
            this.appSecret = appSecret;
        }

        //得到数据包,返回使用页面  
        public System.Collections.Hashtable getSignPackage()
        {
            string jsapiTicket = getJsApiTicket();
            string url_req = HttpContext.Current.Request.Url.ToString();
            //当前网页的URL
            string pageurl = HttpContext.Current.Request.Url.AbsoluteUri;
            writeLog.WriteLogs("当前网页的URL:" + pageurl + "");
            //string url = "http://" + HttpContext.Current.Request.ServerVariables["Http_Host"] + HttpContext.Current.Request.ApplicationPath;
            string timestamp = Convert.ToString(ConvertDateTimeInt(DateTime.Now));
            string nonceStr = createNonceStr();

            // 这里参数的顺序要按照 key 值 ASCII 码升序排序  
            string rawstring = "jsapi_ticket=" + jsapiTicket + "&noncestr=" + nonceStr + "&timestamp=" + timestamp + "&url=" + pageurl + "";
            writeLog.WriteLogs("rawstring:" + rawstring + "");
            string signature = SHA1_Hash(rawstring);

            System.Collections.Hashtable signPackage = new System.Collections.Hashtable();
            signPackage.Add("appId", appId);
            signPackage.Add("nonceStr", nonceStr);
            signPackage.Add("timestamp", timestamp);
            signPackage.Add("url", pageurl);
            signPackage.Add("signature", signature);
            signPackage.Add("jsapiTicket", jsapiTicket);
            return signPackage;
        }

        //创建随机字符串  
        private string createNonceStr()
        {
            int length = 16;
            string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            string str = "";
            Random rad = new Random();
            for (int i = 0; i < length; i++)
            {
                str += chars.Substring(rad.Next(0, chars.Length - 1), 1);
            }
            return str;
        }

        //SHA1哈希加密算法  
        public string SHA1_Hash(string str_sha1_in)
        {
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            byte[] bytes_sha1_in = System.Text.UTF8Encoding.Default.GetBytes(str_sha1_in);
            byte[] bytes_sha1_out = sha1.ComputeHash(bytes_sha1_in);
            string str_sha1_out = BitConverter.ToString(bytes_sha1_out);
            str_sha1_out = str_sha1_out.Replace("-", "").ToLower();
            return str_sha1_out;
        }

        //得到ticket 如果文件里时间 超时则重新获取  
        private string getJsApiTicket()
        {
            //这里我从数据库读取
            string strSql = "select jsapi_ticket,ticket_expires,add_time from dt_weixin_jsapiticket where ID=1";
            DataSet ds = sqlhelp.ExecuteDataSet(strSql);
            DT = ds.Tables[0];
            int expire_time = Convert.ToInt32(DT.Rows[0]["ticket_expires"]);
            string ticket = DT.Rows[0]["jsapi_ticket"].ToString();
            string error = string.Empty;
            string accessToken = new WXCRMComm().GetAccessToken(out error);  //获取系统的全局token 
            writeLog.WriteLogs("获取系统的全局token :" + accessToken + "," + error + "");
            if (string.IsNullOrEmpty(error))
            {
                writeLog.WriteLogs("GetAccessToken:" + error + "");
                //计算时间判断是否过期
                TimeSpan ts = DateTime.Now - DateTime.Parse(DT.Rows[0]["add_time"].ToString());
                double chajunSecond = ts.TotalSeconds;
                if (chajunSecond >= 1200)
                {
                    writeLog.WriteLogs("jsapiticket计算时间判断是否过期:已过期");
                    string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi";
                    Jsapi api = JsonConvert.DeserializeObject<Jsapi>(httpGet(url));
                    ticket = api.ticket;
                    if (ticket != "")
                    {
                        expire_time = ConvertDateTimeInt(DateTime.Now) + 1200;
                        //存入数据库操作
                        strSql = " update dt_weixin_jsapiticket set jsapi_ticket=\'" + ticket + "\',ticket_expires=\'" + expire_time + "\',add_time=\'" + DateTime.Now + "\' where ID=1";
                        sqlhelp.ExecuteNonQuery(strSql);
                    }
                }
                writeLog.WriteLogs("jsapiticket计算时间判断是否过期:没过期");
            }
            return ticket;
        }

        /// <summary>  
        /// 将c# DateTime时间格式转换为Unix时间戳格式  
        /// </summary>  
        /// <param name="time">时间</param>  
        /// <returns>double</returns>  
        public int ConvertDateTimeInt(System.DateTime time)
        {
            int intResult = 0;
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            intResult = Convert.ToInt32((time - startTime).TotalSeconds);
            return intResult;
        }

        //发起一个http请球,返回值  
        private string httpGet(string url)
        {
            try
            {
                WebClient MyWebClient = new WebClient();
                MyWebClient.Credentials = CredentialCache.DefaultCredentials;//获取或设置用于向Internet资源的请求进行身份验证的网络凭据  
                Byte[] pageData = MyWebClient.DownloadData(url); //从指定网站下载数据  
                string pageHtml = System.Text.Encoding.Default.GetString(pageData);  //如果获取网站页面采用的是GB2312,则使用这句              
                return pageHtml;
            }
            catch (WebException webEx)
            {
                Console.WriteLine(webEx.Message.ToString());
                return null;
            }
        }

        #region 创建Json序列化 及反序列化类目  
        //
        /// <summary>
        /// 创建JSon类 保存文件 jsapi_ticket.json  
        /// </summary>
        public class JSTicket
        {
            public string jsapi_ticket { get; set; }

            public double expire_time { get; set; }
        }

        /// <summary>
        /// 创建 JSon类 保存文件 access_token.json  
        /// </summary>
        public class AccToken
        {
            public string access_token { get; set; }

            public double expires_in { get; set; }
        }

        /// <summary>
        /// 创建从微信返回结果的一个类 用于获取ticket  
        /// </summary>

        public class Jsapi
        {
            public int errcode { get; set; }

            public string errmsg { get; set; }

            public string ticket { get; set; }

            public string expires_in { get; set; }
        }
        #endregion
    }

上述代码中负责获取和刷新的 WXCRMComm 类如下:

/// <summary>
    /// 负责获取或刷新AccessToken
    /// </summary>
    public class WXCRMComm
    {
        public WXCRMComm()
        { }

        private string appid;
        private string appsecret;
        BLLweixin_access_token tokenBLL = new BLL.BLLweixin_access_token(); //账户AccessToken 此处根据自己项目单独特别处理
        BLLweixin_account accountBLL = new BLL.BLLweixin_account(); //公众平台账户  此处根据自己项目单独特别处理

        /// <summary>
        /// 及时获得access_token值
        /// access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒,
        /// 重复获取将导致上次获取的access_token失效。
        /// 每日限额获取access_token.我们将access_token保存到数据库里,间隔时间为20分钟,从微信公众平台获得一次。
        /// </summary>
        public string GetAccessToken(out string error)
        {
            string access_token = string.Empty;
            error = string.Empty;
            try
            {
                Model.weixin_account accountModel = accountBLL.GetModel(); //公众平台账户信息
                if (accountModel == null || string.IsNullOrEmpty(accountModel.appid) || string.IsNullOrEmpty(accountModel.appsecret))
                {
                    error = "AppId或者AppSecret未填写,请在补全信息!";
                    return string.Empty;
                }
                //没有找到该账户则获取AccessToKen写入存储1200秒
                if (!tokenBLL.Exists())
                {
                    var result = Senparc.Weixin.MP.CommonAPIs.CommonApi.GetToken(accountModel.appid, accountModel.appsecret);
                    access_token = result.access_token;
                    tokenBLL.Add(access_token);
                    return access_token;
                }
                //获取公众账户的实体
                Model.weixin_access_token tokenModel = tokenBLL.GetModel();
                //计算时间判断是否过期
                TimeSpan ts = DateTime.Now - tokenModel.add_time;
                double chajunSecond = ts.TotalSeconds;
                if (string.IsNullOrEmpty(tokenModel.access_token) || chajunSecond >= tokenModel.expires_in)
                {
                    writeLog.WriteLogs("GetAccessToken:重新修改");
                    //从微信平台重新获得AccessToken
                    var result = Senparc.Weixin.MP.CommonAPIs.CommonApi.GetToken(accountModel.appid, accountModel.appsecret);
                    access_token = result.access_token;
                    //更新到数据库里的AccessToken
                    tokenModel.access_token = access_token;
                    tokenModel.add_time = DateTime.Now;
                    bool ret=tokenBLL.Update(tokenModel);
                    writeLog.WriteLogs("GetAccessToken:重新修改"+ ret + "");
                }
                else
                {
                    writeLog.WriteLogs("GetAccessToken:获取旧的");
                    access_token = tokenModel.access_token;
                }
            }
            catch (Exception ex)
            {
                error = "获取AccessToken出错:" + ex.Message;
            }
            return access_token;
        }

        /// <summary>
        ///【强制刷新】access_token值
        /// access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒,
        /// 重复获取将导致上次获取的access_token失效。
        /// 每日限额获取access_token.我们将access_token保存到数据库里,间隔时间为20分钟,从微信公众平台获得一次。
        /// </summary>
        /// <returns></returns>
        public string FlushAccessToken(out string error)
        {
            string access_token = string.Empty;
            error = string.Empty;
            try
            {
                Model.weixin_account accountModel = accountBLL.GetModel(); //公众平台账户信息
                if (string.IsNullOrEmpty(accountModel.appid) || string.IsNullOrEmpty(accountModel.appsecret))
                {
                    error = "AppId或者AppSecret未填写,请在补全信息!";
                    return "";
                }

                var result = Senparc.Weixin.MP.CommonAPIs.CommonApi.GetToken(accountModel.appid, accountModel.appsecret);
                access_token = result.access_token;

                //没有找到该账户则获取AccessToKen写入存储1200秒
                if (!tokenBLL.Exists())
                {
                    tokenBLL.Add(access_token);
                }
                else
                {
                    //获取公众账户的实体
                    Model.weixin_access_token tokenModel = tokenBLL.GetModel();
                    //更新到数据库里的AccessToken
                    tokenModel.access_token = access_token;
                    tokenModel.add_time = DateTime.Now;
                    tokenBLL.Update(tokenModel);
                }
            }
            catch (Exception ex)
            {
                error = "获得AccessToken出错:" + ex.Message;
            }
            return access_token;
        }

        /// <summary>
        /// 获得所有关注用户的openid字符串(别的方法调用此方法)
        /// </summary>
        private IList<string> BaseUserOpenId(out string error)
        {
            IList<string> ret = new List<string>();

            string access_token = GetAccessToken(out error);
            if (error != "")
            {
                return null;
            }
            Senparc.Weixin.MP.AdvancedAPIs.User.OpenIdResultJson openidJson = Senparc.Weixin.MP.AdvancedAPIs.UserApi.Get(access_token, string.Empty);
            if (openidJson.count == openidJson.total)
            {
                ret = openidJson.data.openid;
            }
            else
            {
                GetNextUserOpenId(openidJson.next_openid, ret);
            }
            return ret;
        }

        /// <summary>
        /// (基础方法)获得所有关注用户的openid字符串(递归算法)
        /// </summary>
        private void GetNextUserOpenId(string nexOpenid, IList<string> openidList)
        {
            string err = string.Empty;
            string access_token = GetAccessToken(out err);
            Senparc.Weixin.MP.AdvancedAPIs.User.OpenIdResultJson openidJson = Senparc.Weixin.MP.AdvancedAPIs.UserApi.Get(access_token, nexOpenid);
            if (openidJson == null || openidJson.count <= 0)
            {
                return;
            }
            else
            {
                for (int i = 0; i < openidJson.data.openid.Count; i++)
                {
                    openidList.Add(openidJson.data.openid[i]);
                }
                GetNextUserOpenId(openidJson.next_openid, openidList);
            }
        }

        #region 消息群发处理===================================
        /// <summary>
        /// 上传永久素材
        /// </summary>
        public string UploadForeverMedia(string imgFullPath, out string error)
        {
            string accessToken = GetAccessToken(out error);
            if (!string.IsNullOrEmpty(error))
            {
                return string.Empty;
            }
            var result = Senparc.Weixin.MP.AdvancedAPIs.MediaApi.UploadForeverMedia(accessToken, imgFullPath);
            if (result.errcode == 0)
            {
                return result.media_id;
            }
            error = result.errmsg;
            return string.Empty;
        }

        /// <summary>
        /// 删除永久素材
        /// </summary>
        public bool DeleteForeverMedia(string mediaId, out string error)
        {
            string accessToken = GetAccessToken(out error);
            if (!string.IsNullOrEmpty(error))
            {
                return false;
            }
            var result = Senparc.Weixin.MP.AdvancedAPIs.MediaApi.DeleteForeverMedia(accessToken, mediaId);
            if (result.errcode != 0)
            {
                error = result.errmsg;
                return false;
            }
            error = string.Empty;
            return true;
        }

        /// <summary>
        /// 群发消息
        /// </summary>
        public bool SendGroupMessageByGroupId(List<Senparc.Weixin.MP.AdvancedAPIs.GroupMessage.NewsModel> ls, out string error)
        {
            string accessToken = GetAccessToken(out error);
            //新增素材
            var result1 = Senparc.Weixin.MP.AdvancedAPIs.MediaApi.UploadNews(accessToken, 10000, ls.ToArray());
            if (result1.errcode != 0)
            {
                error = result1.errmsg;
                return false;
            }
            //群发消息
            var result2 = Senparc.Weixin.MP.AdvancedAPIs.GroupMessageApi.SendGroupMessageByGroupId(accessToken, "0", result1.media_id, Senparc.Weixin.MP.GroupMessageType.mpnews, true);
            if (result2.errcode != 0)
            {
                error = result2.errmsg;
                return false;
            }
            error = string.Empty;
            return true;
        }
        #endregion

    }

另外,微信接口类 继承 了 DBBase ,里面只有连接数据库对象,这个可以根据自己项目特点和需要处理 这里只做演示:

   public class DBBase
    {
        protected static string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
        public SqlHelper sqlhelp = new SqlHelper(connectionString);
    }

上述代码中SqlHelper 通用帮助类 也贴一下吧,仅供参考

/// <summary>
    /// SqlHelper操作类
    /// </summary>
    public sealed partial class SqlHelper
    {
        /// <summary>
        /// 批量操作每批次记录数
        /// </summary>
        public static int BatchSize = 2000;

        /// <summary>
        /// 超时时间
        /// </summary>
        public static int CommandTimeOut = 600;

        /// <summary>
        ///初始化SqlHelper实例
        /// </summary>
        /// <param name="connectionString">数据库连接字符串</param>
        public SqlHelper(string connectionString)
        {
            this.ConnectionString = connectionString;
        }

        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        public string ConnectionString { get; set; }

        #region 实例方法

        #region ExecuteNonQuery

        /// <summary>
        /// 执行SQL语句,返回影响的行数
        /// </summary>
   

以上是关于微信朋友圈转发第三方网站带缩略图实现的主要内容,如果未能解决你的问题,请参考以下文章

微信分享,如何更改转发描述和缩略图?

两步实现微信小程序分享朋友圈

#yyds干货盘点# 织梦微信分享开发

微信转发朋友圈小视频就这么简单

H5网页实现微信分享,分享朋友圈功能(分享带图片,附源码)

H5网页实现微信分享,分享朋友圈功能(分享带图片,附源码)