微信接口图文消息群发,预览

上来就直接贴代码了,具体问题放到最后说,这个类我将方法全都封装在里面了,基本上拿去修改一下就可以用了

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Text.RegularExpressions;

using Newtonsoft.Json;

using System.Web.SessionState;

using Website_CS;

using mgtArticle.mgtArticle;

using System.Net;

using System.Text;

using System.IO;

using System.Data;

using BHWeb;

namespace mgtArticle.wxArticle

{

    //此类用于微信功能

    public class WebChatHelper

    {

        private Regex _regex = new Regex(@"{.*}", RegexOptions.IgnoreCase);

        #region 获取access_token

        /// <summary>

        ///  获取access_token

        /// </summary>

        /// <param name="redirect_uri">请求acess_token的地址</param>

        /// <param name="appId">微信appID</param>

        /// <param name="appSecret">微信appSecret</param>

        /// <returns>access_token</returns>

        public string GetAccessToken(string redirect_uri, string appId, string appSecret)

        {

            HttpHelper helper = new HttpHelper();

            string access_token = "";

            //获取access_token、openId

            string access_Token_Url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appId, appSecret);

            string get_Token = helper.GetPageResponse_Get(access_Token_Url, redirect_uri, "*/*");

            if (_regex.IsMatch(get_Token))

                get_Token = _regex.Match(get_Token).Value;

            var result = JsonConvert.DeserializeObject<Get_Access_token>(get_Token);

            access_token = result.Access_Token;

                return access_token;

        }

        /// <summary>

        /// 上传文件

        /// </summary>

        /// <param name="access_token">微信返回的access_token</param>

        /// <param name="type">上传文件的类型</param>

        /// <param name="path"></param>

        /// <returns></returns>

        private static string UploadFile(string access_token, string type, string path)

        {

            // 设置参数

            string url = string.Format("http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token={0}&type={1}", access_token, type);

            return HttpUploadFile(url, path);

        }

        private static string UploadImg(string access_token, string path)

        {

            // 设置参数

            string url = string.Format("https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={0}", access_token);

            return HttpUploadFile(url, path);

        }

        /// <summary>

        /// Http上传文件

        /// </summary>

        public static string HttpUploadFile(string url, string path)

        {

            // 设置参数

            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

            CookieContainer cookieContainer = new CookieContainer();

            request.CookieContainer = cookieContainer;

            request.AllowAutoRedirect = true;

            request.Method = "POST";

            string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线

            request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;

            byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("rn--" + boundary + "rn");

            byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("rn--" + boundary + "--rn");

            int pos = path.LastIndexOf("");

            string fileName = path.Substring(pos + 1);

            //请求头部信息 

            StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name="file";filename="{0}"rnContent-Type:application/octet-streamrnrn", fileName));

            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());

            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);

            byte[] bArr = new byte[fs.Length];

            fs.Read(bArr, 0, bArr.Length);

            fs.Close();

            Stream postStream = request.GetRequestStream();

            postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);

            postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

            postStream.Write(bArr, 0, bArr.Length);

            postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);

            postStream.Close();

            //发送请求并获取相应回应数据

            HttpWebResponse response = request.GetResponse() as HttpWebResponse;

            //直到request.GetResponse()程序才开始向目标网页发送Post请求

            Stream instream = response.GetResponseStream();

            StreamReader sr = new StreamReader(instream, Encoding.UTF8);

            //返回结果网页(html)代码

            string content = sr.ReadToEnd();

            return content;

        }

        #endregion

        #region 拼接图文内容

        /// <summary>

        /// 拼接图文消息素材Json字符串

        /// </summary>

        /// <param name="access_token">微信获取的access_token</param>

        /// <param name="cIDs">文章的id,用于去数据库读取多个文章用,隔开</param>

        /// <returns>拼接好的微信文章Json数据或错误内容,格式为1|Json数据或-1|错误内容</returns>

        public string GetArticlesJsonStr(string access_token, string cIDs)

        {

            RecordSet RS = new RecordSet(BHSet.ConnString, SqlSelector.MSSql);

            StringBuilder sbArticlesJson = new StringBuilder();

            sbArticlesJson.Append("{"articles":[");//图文消息,一个图文消息支持1到10条图文 

            string[] arr_id = cIDs.Split(‘,‘);

            for (int i = 0; i < arr_id.Length; i++)

            {

                string sql = "select * from Article where cID=‘" + arr_id[i] + "‘ and iStatus=‘1‘";

                RS.Execute(sql);

                if (RS.RecordCount > 0)

                {

                    foreach (DataRow dr in RS.Rows)

                    {

                        string path = HttpContext.Current.Server.MapPath(getPicurte(dr["cContent"].ToString()));

                        if (!File.Exists(path))

                        {

                            return "-1|要发送的图片不存在";

                        }

                       

                        // 上传图片返回媒体ID

                        string msg = UploadFile(access_token, "image", path);

                        if (_regex.IsMatch(msg))

                            msg = _regex.Match(msg).Value;

                        var result = JsonConvert.DeserializeObject<Get_Media_Id>(msg);

                        string thumb_media_id = result.Media_ID;

                        string noPicContent = GetNoPicarticle(dr["cContent"].ToString());//去除文章内容中的图片地址

                        if (noPicContent.Length > 54)

                            noPicContent = noPicContent.Substring(0, 53);

                        string changePicContent = GetReplacePic(dr["cContent"].ToString(),access_token);//替换文章内容中的图片地址

                        sbArticlesJson.Append("{");

                        sbArticlesJson.Append(""thumb_media_id":"" + thumb_media_id + "",");

                        sbArticlesJson.Append(""author":"律桥法律平台",");

                        sbArticlesJson.Append(""title":"" + dr["cTitle"].ToString() + "",");

                        sbArticlesJson.Append(""content_source_url":"http://www.lvqiao.net/Mobile/ArticleDetail.aspx?cID=" + dr["cID"].ToString() + "",");//在图文消息页面点击“阅读原文”后的页面 

                        sbArticlesJson.Append(""content":"" + changePicContent + "",");//图文消息页面的内容,支持HTML标签。具备微信支付权限的公众号,可以使用a标签,其他公众号不能使用 

                        sbArticlesJson.Append(""digest":"" + noPicContent + "",");//图文消息的描述 

                        sbArticlesJson.Append(i == arr_id.Length - 1 ? ""show_cover_pic":"0"}" : ""show_cover_pic":"0"},");//  是否显示封面,1为显示,0为不显示 

                    }

                }

            }

            sbArticlesJson.Append("]}");

            return "1|"+sbArticlesJson.ToString();

        }

        //获取文章内容中第一张的图片路径

        private string getPicurte(string cContent)

        {

            string src = "";

            int iIndex = 0;

            int iEnd = 0;

            try

            {

                iIndex = cContent.ToLower().IndexOf("src="");

                if (iIndex > 0)

                {

                    iIndex = cContent.ToLower().IndexOf(""", iIndex);

                    iEnd = cContent.ToLower().IndexOf(""", iIndex + 2);

                    src = cContent.Substring(iIndex, iEnd - iIndex);

                    src = src.Replace(""", "").Replace("src=", "");

                }

                else

                {

                    src = "";

                }

            }

            catch (Exception ex)

            {

                src = ex.Message + "(" + iIndex + "," + iEnd + ")";

            }

            return src;

        }

        #endregion

        #region 获取文章的media_id

        /// <summary>

        /// 请求Url,发送数据

        /// </summary>

        public static string PostUrl(string url, string postData)

        {

            byte[] data = Encoding.UTF8.GetBytes(postData);

            // 设置参数

            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

            CookieContainer cookieContainer = new CookieContainer();

            request.CookieContainer = cookieContainer;

            request.AllowAutoRedirect = true;

            request.Method = "POST";

            request.ContentType = "application/x-www-form-urlencoded";

            request.ContentLength = data.Length;

            Stream outstream = request.GetRequestStream();

            outstream.Write(data, 0, data.Length);

            outstream.Close();

            //发送请求并获取相应回应数据

            HttpWebResponse response = request.GetResponse() as HttpWebResponse;

            //直到request.GetResponse()程序才开始向目标网页发送Post请求

            Stream instream = response.GetResponseStream();

            StreamReader sr = new StreamReader(instream, Encoding.UTF8);

            //返回结果网页(html)代码

            string content = sr.ReadToEnd();

            return content;

        }

        /// <summary>

        ///  上传图文消息素材获取media_id

        /// </summary>

        /// <param name="access_token">微信的access_token</param>

        /// <param name="postData">拼接好的微信文章json数据</param>

        /// <returns>media_id</returns>

        public string UploadNews(string access_token, string postData)

        {

            string content = "";

            content = PostUrl(string.Format("https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token={0}", access_token), postData);

            if (_regex.IsMatch(content))

                content = _regex.Match(content).Value;

            var result = JsonConvert.DeserializeObject<Get_Media_Id>(content);

            string media_id = result.Media_ID;

            string type = result.Type;

            string create_at = result.Created_At;

            return media_id;

        }

        #endregion

微信接口图文消息群发,预览

        #region 获取所有关注者的openid

        /// <summary>

        /// 获取关注者OpenID集合

        /// </summary>

        /// <param name="access_token">微信获取的access_token</param>

        /// <param name="redirect_uri">请求获取openid的页面地址</param>

        /// <returns>OpenID集合</returns>

        public List<string> GetOpenIDs(string access_token, string redirect_uri)

        {

            List<string> result = new List<string>();

            List<string> openidList = GetOpenIDs(access_token, null, redirect_uri);

            result.AddRange(openidList);

            while (openidList.Count > 9999)

            {

                openidList = GetOpenIDs(access_token, openidList[openidList.Count - 1], redirect_uri);

                if (openidList.Count > 0)

                    result.AddRange(openidList);

            }

            return result;

        }

        /// <summary>

        /// 获取关注者OpenID集合

        /// </summary>

        public List<string> GetOpenIDs(string access_token, string next_openid,string redirect_uri)

        {

            // 设置参数

            HttpHelper helper = new HttpHelper();

            string url = string.Format("https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}&next_openid={1}", access_token, string.IsNullOrWhiteSpace(next_openid) ? "" : next_openid);

            string returnStr = helper.GetPageResponse_Get(url, redirect_uri, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");

            List<string> list = new List<string>();

            var result_list = JsonConvert.DeserializeObject<Get_OpenID>(returnStr);

            if (result_list.Data.OpenID.Length > 0)

            {

                string[] resule_data = result_list.Data.OpenID;

                list.AddRange(resule_data);

            }

            return list;

        }

        #endregion

        #region 拼接图文消息

        /// <summary>

        /// 拼接图文消息json

        /// </summary>

        /// <param name="media_id"></param>

        /// <param name="openidList"></param>

        /// <returns></returns>

        public string CreateNewsJson(string media_id, List<string> openidList)

        {

            StringBuilder sb = new StringBuilder();

            sb.Append("{"touser":[");

            sb.Append(string.Join(",", openidList.ConvertAll<string>(a => """ + a + """).ToArray()));

            sb.Append("],");

            sb.Append(""mpnews":{"media_id":"" + media_id + ""},");

            sb.Append(""msgtype":"mpnews"");

            sb.Append("}");

            return sb.ToString();

        }

        /// <summary>

        /// 拼接图文消息(用于预览),只能使用单一的微信号或者微信openid,需手动更改

        /// </summary>

        /// <param name="media_id"></param>

        /// <returns></returns>

        public string CreateNewsJson2(string media_id)

        {

            BSet b = new BSet("9000");

            StringBuilder sb = new StringBuilder();

            sb.Append("{"towxname":""+b.cCode2+"",");

            sb.Append(""msgtype":"mpnews",");

            sb.Append(""mpnews":{"media_id":"" + media_id + ""}");

            sb.Append("}");

            return sb.ToString();

        }

        /// <summary>

        /// 根据OpenID列表群发

        /// </summary>

        public string Send(string access_token, string postData, string redirect_uri)

        {

            HttpHelper helper = new HttpHelper();

            return helper.GetPageResponse_Post(string.Format("https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token={0}", access_token), postData, redirect_uri);

        }

        #endregion

        #region 微信接口预览

        /// <summary>

        /// 预览接口

        /// </summary>

        /// <param name="access_token">access_token</param>

        /// <param name="media_id">消息的media_id</param>

        /// <param name="openidList">用户openidList数组</param>

        /// <param name="redirect_uri">请求页面的地址</param>

        /// <param name="postData">文章内容</param>

        /// <returns></returns>

        public string previewMsg(string access_token, string postData, string redirect_uri)

        {

            HttpHelper helper = new HttpHelper();

            return helper.GetPageResponse_Post(string.Format("https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token={0}", access_token), postData, redirect_uri);

        }

        #endregion

        #region Utility

        /// <summary>

        /// 生成随机字母字符串(数字字母混和)

        /// </summary>

        public static string GenerateCheckCode()

        {

            int rep = 0;

            string str = string.Empty;

            long num2 = DateTime.Now.Ticks + rep;

            rep++;

            Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep)));

            for (int i = 0; i < 15; i++)

            {

                char ch;

                int num = random.Next();

                if ((num % 2) == 0)

                {

                    ch = (char)(0x30 + ((ushort)(num % 10)));

                }

                else

                {

                    ch = (char)(0x41 + ((ushort)(num % 0x1a)));

                }

                str = str + ch.ToString();

            }

            return str;

        }

        /// <summary>

        /// 获取没有图片的文章内容

        /// </summary>

        public string  GetNoPicarticle(string content) {

            string str = "<img(.*?)(src)="(?!.*?logo).*>";

            Regex regex = new Regex(str);

            foreach(Match re in regex.Matches(content)){

                content = content.Replace(re.Value, "");

            }

            content = content.Replace(""", "‘").Replace("<p>","").Replace("</p>","");

            content = content.Replace("<label>", "").Replace("</label>", "").Replace("<span>", "</span>");

            return content;

        }

        /// <summary>

        /// 替换文章内的图片链接

        /// </summary>

        /// <returns></returns>

        public string GetReplacePic(string content, string access_token)

        {

            string str = @"<img.*?src=""([^""]*)"".*?>";

            Regex regex = new Regex(str);

            foreach (Match re in regex.Matches(content))//匹配出所有src

            {

               

                    ////获取图片在微信的url

                    string wx_url = UploadImg(access_token, HttpContext.Current.Server.MapPath(re.Groups[1].Value));

                    if (_regex.IsMatch(wx_url))

                        wx_url = _regex.Match(wx_url).Value;

                    var result_url = JsonConvert.DeserializeObject<Get_ImgUrl>(wx_url);

                    string url = result_url.URL;

               

                string result = re.Groups[1].Value.Replace(re.Groups[1].Value, url);

                content = content.Replace(re.Groups[1].Value, result);

                

            }

            content = content.Replace(""", "‘");

            return content;

        }

        #endregion

        #region Json

        //Json解析

        public class Get_Access_token

        {

            [JsonProperty("access_token")]

            public string Access_Token { get; set; }

            [JsonProperty("expires_in")]

            public string Expires_In { get; set; }

        }

        public class ErrorCode

        {

            [JsonProperty("errcode")]

            public string ErrCode { get; set; }

            [JsonProperty("errmsg")]

            public string ErrMsg { get; set; }

            [JsonProperty("msg_id")]

            public string Msg_ID { get; set; }

            [JsonProperty("msg_data_id")]

            public string Msg_Data_ID { get; set; }

        }

        public class Get_Media_Id

        {

            //  媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb),次数为news,即图文消息 

            [JsonProperty("type")]

            public string Type { get; set; }

            //  媒体文件/图文消息上传后获取的唯一标识 

            [JsonProperty("media_id")]

            public string Media_ID { get; set; }

            //  媒体文件上传时间 

            [JsonProperty("created_at")]

            public string Created_At { get; set; }

            // [JsonProperty("thumb_media_id")]

            //public string Thumb_media_id { get; set; }

        }

        public class Get_OpenID

        {

            //媒体文件类型ID

            [JsonProperty("total")]

            public string Total { get; set; }

            [JsonProperty("count")]

            public string Count { get; set; }

            [JsonProperty("data")]

            public Get_OpenIDs Data { get; set; }

            [JsonProperty("next_openid")]

            public string Next_Openid { get; set; }

        }

        public class Get_OpenIDs

        {

            //关注者列表ID

            [JsonProperty("openid")]

            public string[] OpenID { get; set; }

        }

        public class Get_ImgUrl

        {

            //图片在微信的地址

            [JsonProperty("url")]

            public string URL { get; set; }

        }

        #endregion

    }

}

 
 
 
 
方法调用
 
 /// <summary>
    /// WebChatMsgSub 微信接口调用
    /// </summary>
    public class WebChatMsgSub : IHttpHandler, IReadOnlySessionState
    {
        private Regex _regex = new Regex(@"{.*}", RegexOptions.IgnoreCase);
        public string cIDs = "";
        public string appId = "xxxxxx";//微信appId
        public string appSecret = "xxxxx";//微信appSecret
        public string access_token = "",
                        media_id = "",
                        postData = "",
                        ops = "",
                        openidlist = "",
                        redirect_uri = "",
                        wx_result="",
                        end_content = "";
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
 
 
            WebChatHelper wx_helper = new WebChatHelper();
            cIDs = HttpUtility.UrlDecode(SqlRequest.Get("cIDs"));//获取文章的数量
            string subType = SqlRequest.Get("subType");//0:预览接口 1:发送图文消息
            string content = "", p_0 = "";
            #region 获取access_token
            redirect_uri = context.Request.Url.ToString();
            access_token = wx_helper.GetAccessToken(redirect_uri, appId, appSecret);
            if (string.IsNullOrEmpty(access_token))
            {
                context.Response.Write("access_token获取失败"); return;
            }
            #endregion
            #region 拼接图文内容
            content = wx_helper.GetArticlesJsonStr(access_token, cIDs);
            p_0 = content.Split(‘|‘)[0];
            postData = content.Split(‘|‘)[1];
            if (p_0 == "-1")
            {
                context.Response.Write(postData); return;
            }
            //context.Response.Write(postData); return;
            #endregion
            #region 获取本次消息的media_id
            media_id = wx_helper.UploadNews(access_token, postData);
            if (string.IsNullOrEmpty(media_id))
            {
                context.Response.Write("media_id获取失败"); return;
            }
           
            #endregion
            switch (subType)
            {
                case "0":
                    #region 拼接预览图文json
                    end_content = wx_helper.CreateNewsJson2(media_id);
                    #endregion
                    wx_result=wx_helper.previewMsg(access_token, end_content, redirect_uri);
                    break;
                case "1":
                    #region 获取所有openid集合
                    List<string> openidList = new List<string>();
                    openidList = wx_helper.GetOpenIDs(access_token, redirect_uri);
                    //ops = "";
                    //for (int i = 0; i < openidList.Count; i++)
                    //{
                    //    ops += openidList[i] + ",";
                    //}
                    #endregion
                    #region 拼接图文json
                    end_content = wx_helper.CreateNewsJson(media_id, openidList);
                    #endregion
                    wx_result=wx_helper.Send(access_token, end_content, redirect_uri);
                    break;
            }
            //结果处理
            if (_regex.IsMatch(wx_result))
                wx_result = _regex.Match(wx_result).Value;
            var result = JsonConvert.DeserializeObject<ErrorCode>(wx_result);
            string errcode = result.ErrCode;
            if (errcode != "0")
                context.Response.Write("发送失败-错误码:" + errcode + "-消息:" + result.ErrMsg);
            else
                context.Response.Write("发送成功!");
 
        }
 
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
 
        public class ErrorCode
        {
 
            [JsonProperty("errcode")]
            public string ErrCode { get; set; }
 
            [JsonProperty("errmsg")]
            public string ErrMsg { get; set; }
 
            [JsonProperty("msg_id")]
            public string Msg_ID { get; set; }
 
            [JsonProperty("msg_data_id")]
            public string Msg_Data_ID { get; set; }
        }
 
    }
 
这里说一下需要注意的问题,也困扰了我很久的问题,在网上找了一天才找到答案所在,关于这个借口的问题网上的帮助实在太少了,所以就在这里发出一下做个记录,希望能够帮助到更多跟我一样的初学者。  PS,这些内容我也是在前人的基础上进行修改的,因为只有简单的一个功能,没有跟其他大神那样繁杂的框架,所以应该很容易看懂的。
 
问题一:刚开始我发送时,本以为发送成功了,但始终只有一张图片(也就是单图文消息,而且描述没有显示,点击阅读全文也没有内容),因为我是直接勾选多篇文章直接发送的,所以在文章拼接时肯定出了问题,但我找了很久都没有发现问题,因为比对过腾讯的技术文档,数据一样的,所以困扰了我一整天。
最后终于发现了原因,就是因为在文章拼接的时候content的内容一定不能有双引号!不然你就爽了!所以我在填写文章内容的时候,先用 content = content.Replace(""", "‘");替换内容里的双引号,这样就没问题了~
 
问题二:发送成功之后,图文消息详情页只显示第一张图片,其他都没有读取,这个问题就是因为你没有将其他图片上传到腾讯获取他的url替换到你自己的图片地址中,这个技术文档上也有说,但一开始总让我看不懂,他只是说获取media_id的时候用,却特么没告诉我其他图片也要用到这个url!不过这个问题倒没花多少时间,主要是上面的问题。
 
问题三:文章的描述内容那里直接将html输出了,这个我的解决办法是,直接去除常用的标签,只留下文章内容,方法比较笨,但总算暂时解决了问题~我猜测那个文章的描述应该是不支持html的,跟content不同,好了,内容就说到这里,希望能帮助到大家
 

相关文章