微信公众账号开发之N个坑(一)

我这人干活没有前奏,喜欢直接开始。完了,宝宝已经被你们带污了。。

微信公众账号开发文档,官方版(https://mp.weixin.qq.com/wiki),相信我,我已经无力吐槽写这个文档的人了,我真心想杂碎这个键盘,但是下手之后才发现,原来键盘是我自己花钱买的。。。。尴尬了。

废话不说,直接说怎么部署,怎么开发。

首先,你得有一个公众平台账号,好了,开始计坑。

第一坑,不要以为不是企业号就不能开发了,可以申请测试号的,比所谓的订阅号接口多多了。

进入后台管理之后,点击开发者工具,可以看到公众平台测试账号,直接进入即可。开始填写自己的配置。

注意涂鸦部分,这部分是程序中必须要配置的东东,如果没有配置的话,这是一定不成功的。

第二坑,当然,你这么配置也一定是不成功的,不要问我为什么。没图说个几把。。。(https://mp.weixin.qq.com/wiki)

请不要认为企鹅帝闹着玩,这是真的,必须是80端口,其实也就发布一个域名的网站即可。因为域名的网站都是80端口出来的,继续说正题。

企鹅帝告诉我们,要用微信账号,必须有一台服务器,然后配置我们发布的网站就行了,请注意,token是自己设定的,这个不是自动生成的,自己设定。。URL就是我们发布的网站名称

第三坑,网站不发布,接口配置信息是永远配置不过去的,记住,是永远。

JS接口安全域名,这个请直接参考文档(http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html)。

JS接口安全域名的目的是为了下载图片,调用微信图片接口等等,比如当你需要调用摄像头的时候,或者说说需要上传照片的时候,这时候就需要JS安全接口了,关于具体的内容暂不做详细描述。

在微信公众账号测试号的版本后台中,有一个体验接口权限表里面的这一项也是必须配置的。也不算是必须配置,而是这个接口可以获取到微信用户的部分信息。值得提醒的是每个公众账号对应的每个ID是唯一的,也就是说,即便网站内网不变,如果换了公众号,那么,这时候的微信公众号的数据是不能共通的,只是相对公共号唯一。

第四坑,申请微信网页授权的时候,这里的网页授权用户基本信息,这个本身没问题,但是没有提示就有问题了。

这里的网址,请注意,一定是不含www的,而且后面没有反斜杠,也就是说这里的网址的回调格式是  abc.de.com 或者直接是一级域名也可以,OK,请记住这个格式,必须这么干。好了,服务器暂且这样,暂开始用代码说话。

首先从服务器验证说起。这个在官网是有例子的,不过是PHP的,其实说白了首先就是验证一个随机数,然后在POST的情况下,检测返回值即可。直接上代码

        public ActionResult Index()
        {
            if (Request.HttpMethod.ToLower() == "post")
            {
                if (CheckSignature())//验证服务器是否通过
                {
                    GetMenuList();//加载菜单
                }
                else
                {
                    Response.Write("<h1>Oh</h1><h2>我们相遇在火星吧!!!</h2>");
                    Response.End();
                }
            }
            else
            {
                CheckWechat();
            }
            return View();
        }

        /// <summary>
        /// 返回随机数表示验证成功
        /// </summary>
        private void CheckWechat()
        {
            if (string.IsNullOrEmpty(Request.QueryString["echoStr"]))
            {
                Response.Write("消息并非来自微信");
                Response.End();
            }
            string echoStr = Request.QueryString["echoStr"];
            if (CheckSignature())
            {
                Response.Write(echoStr);
                Response.End();
            }
        }
	/// <summary>
        /// 验证微信签名
        /// </summary>
        /// <returns></returns>
        /// 将token、timestamp、nonce三个参数进行字典序排序
        /// 将三个参数字符串拼接成一个字符串进行sha1加密
        /// 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信。
        private bool CheckSignature()
        {
            string signature = Convert.ToString(Request["signature"]);
            string timestamp = Convert.ToString(Request["timestamp"]);
            string nonce = Convert.ToString(Request["nonce"]);
            string[] ArrTmp = { Token, timestamp, nonce };
            Array.Sort(ArrTmp);   //字典排序
            string tmpStr = string.Join("", ArrTmp);
            tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
            tmpStr = tmpStr.ToLower();
            if (tmpStr == signature)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

然后,公众平台在有权限的情况下是自定义菜单的,但是一旦开始自定义菜单,原来的手动编辑的菜单是不能用的,也就是说,如果服务器验证通过,那么必须用自己的代码控制。

我们一起来看GetMenuList()这个方法,这个其实很简单的,就是随便凭借一个JSON格式字符串。然后调用微信的接口即可。  public void GetMenuList()

     {
         string weixin1 = "";
         weixin1 = @" {
     ""button"":[
     {
          ""type"":""click"",
          ""name"":""你好!"",
          ""key"":""hello""
      },
      {
           ""type"":""view"",
           ""name"":""公司简介"",
           ""url"":""http://www.xnfhtech.com""
      },
      {
           ""name"":""产品介绍"",
           ""sub_button"":[
            {
               ""type"":""click"",
               ""name"":""产品1"",
                ""key"":""p1""
            },
            {
               ""type"":""click"",
               ""name"":""产品2"",
               ""key"":""p2""
            }]
       }]  }";  

         string access_token = Tools.WA_GetAccess_Token.IsExistAccess_Token();
         string i = this.MenuCreate(menu, access_token);
         Response.Write(i);
     }

    	public string MenuCreate(string MenuJson, string access_token)
        {
            JavaScriptSerializer Jss = new JavaScriptSerializer();
            string setMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}";
            setMenuUrl = string.Format(setMenuUrl, access_token);//获取token、拼凑url
            string respText = WebRequestPostOrGet(setMenuUrl, MenuJson);
            Dictionary<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(respText);
            return respDic["errcode"].ToString();//返回0发布成功
        }

 	/// <summary>
        /// Post/get 提交调用抓取
        /// </summary>
        /// <param name="url">提交地址</param>
        /// <param name="param">参数</param>
        /// <returns>string</returns>
        public string WebRequestPostOrGet(string sUrl, string sParam)
        {
            byte[] bt = System.Text.Encoding.UTF8.GetBytes(sParam);

            Uri uriurl = new Uri(sUrl);
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uriurl);//HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url + (url.IndexOf("?") > -1 ? "" : "?") + param);
            req.Method = "Post";
            req.Timeout = 120 * 1000;
            req.ContentType = "application/x-www-form-urlencoded;";
            req.ContentLength = bt.Length;

            using (Stream reqStream = req.GetRequestStream())//using 使用可以释放using段内的内存
            {
                reqStream.Write(bt, 0, bt.Length);
                reqStream.Flush();
            }
            try
            {
                using (WebResponse res = req.GetResponse())
                {
                    //在这里对接收到的页面内容进行处理
                    Stream resStream = res.GetResponseStream();
                    StreamReader resStreamReader = new StreamReader(resStream, System.Text.Encoding.UTF8);
                    string resLine;
                    System.Text.StringBuilder resStringBuilder = new System.Text.StringBuilder();
                    while ((resLine = resStreamReader.ReadLine()) != null)
                    {
                        resStringBuilder.Append(resLine + System.Environment.NewLine);
                    }
                    resStream.Close();
                    resStreamReader.Close();
                    return resStringBuilder.ToString();
                }
            }
            catch (Exception ex)
            {
                return ex.Message;//url错误时候回报错
            }
        }

  

好吧,我承认我是一个不明真相的吃货,怎么又多了一个access_token=IsExistAccess_Token();呢,莫着急,宝宝告诉你。

当我们阅读文档的时候,我们会发现,这里的Access_Token是每两个小时就过期的。这里的方法就是让他过期的时候自动获取。

第五坑,这里的JSON字符串,也就是要展示的菜单,我希望大家都用小写,如果用了大写,那么,呵呵,哈哈了真心的,很操蛋的,他会告诉你没有用UTF8编码,但是你真心是编码过的,可惜还是出错,所以,还是小写吧,唉

继续说两个小时自动获取之后,就是通过MenuCreate(调用微信菜单接口)输出即可。上代码。

    /// <summary>
    /// 防止每次请求的token两个小时的变化
    /// </summary>
    public class WA_GetAccess_Token
    {
        public WA_GetAccess_Token()
        {
        }

        public static WAEntity.Access_token GetAccess_Token()
        {
            string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ ConfigurationManager.AppSettings["AppID"] + "&secret="+ ConfigurationManager.AppSettings["AppSecret"];
            Access_token entity = new Access_token();
            try
            {
                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
                req.Method = "GET";
                using (WebResponse wr = req.GetResponse())
                {
                    HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();
                    StreamReader reader = new StreamReader(myResponse.GetResponseStream(), System.Text.Encoding.UTF8);
                    string content = reader.ReadToEnd();
                    Access_token token = new Access_token();
                    token = JsonHelper.ParseFromJson<Access_token>(content);
                    entity.access_token = token.access_token;
                    entity.expires_in = token.expires_in;
                }
            }
            catch{ //记录日志}
            return entity;
        }

        /// <summary>
        /// 根据当前日期 判断Access_Token 是否超期  如果超期返回新的Access_Token   否则返回之前的Access_Token
        /// </summary>
        /// <param name="datetime"></param>
        /// <returns></returns>
        public static string IsExistAccess_Token()
        {
            try
            {
                string Token = string.Empty;
                DateTime YouXRQ;
                //读取XML文件中的数据,并显示出来
                string filepath = HttpContext.Current.Request.MapPath("~/XMLFile.xml");
                StreamReader str = new StreamReader(filepath, System.Text.Encoding.UTF8);
                XmlDocument xml = new XmlDocument();
                xml.Load(str);
                str.Close();
                str.Dispose();
                Token = xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText;
                YouXRQ = Convert.ToDateTime(xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText);
                if (DateTime.Now > YouXRQ)
                {
                    DateTime _youxrq = DateTime.Now;
                    WAEntity.Access_token mode = GetAccess_Token();
                    xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText = mode.access_token;
                    _youxrq = _youxrq.AddSeconds(Convert.ToInt32(mode.expires_in));
                    xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText = _youxrq.ToString();
                    xml.Save(filepath);
                    Token = mode.access_token;
                }
                return Token;
            }
            catch (Exception ex)
            {
                return "";//记录日志
            }
        }
    }

    public class Access_token
    {
        public Access_token()
        { }

        public string access_token { get; set; }
        public string expires_in { get; set; }
    }

    public class JsonHelper
    {
        /// <summary>
        /// 生成Json格式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string GetJson<T>(T obj)
        {
            DataContractJsonSerializer json = new DataContractJsonSerializer(obj.GetType());
            using (MemoryStream stream = new MemoryStream())
            {
                json.WriteObject(stream, obj);
                string szJson = Encoding.UTF8.GetString(stream.ToArray()); return szJson;
            }
        }
        /// <summary>
        /// 获取Json的Model
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="szJson"></param>
        /// <returns></returns>
        public static T ParseFromJson<T>(string szJson)
        {
            T obj = Activator.CreateInstance<T>();
            using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(szJson)))
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
                return (T)serializer.ReadObject(ms);
            }
        }
    }

原谅我又不明真相了,所谓的XMLFile.xml这又是什么鬼,好吧,我其实不想说的这么直白的,还是代码直接上比较好。

<?xml version="1.0" encoding="utf-8"?>
<xml>
  <Access_Token>获取TOKEN</Access_Token>
  <Access_YouXRQ>2015/9/12 17:56:31</Access_YouXRQ>
</xml>

我确定这个你真心不想说什么了

好吧,默默的吃着瓜子,静静的看着你们继续,今天就先到这里,随后我们继续走起,已经五个坑了呀,宝宝心里苦呀。

时间: 2025-01-02 19:06:30

微信公众账号开发之N个坑(一)的相关文章

微信公众号开发之js-sdk开发

公司最近项目需要使用微信进行分享,对微信的jssdk研究了下,由于研究过程并不顺利,遇到的坑比较多,所以特意将研究结果记录下来,供大家批评和参考! 官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 微信的jssdk是面向网页开发者提供的基于微信内的网页开发工具包,提供了诸如分享朋友圈,分享微信好友,分享QQ好友 and so on,具体支持的文档参考上述官方文档; 在进行微信jssdk开发之前,首先你得拥

记微信公众平台开发之V3版微信native原生支付功能开发

一.生成商品信息 动态链接支付过程中,是先生成商品交易进行,再来进行支付交易的. 1. 商品信息准备 主要是先定义商品的名称及价格,以及交易号.代码如下. include_once("../WxPayPubHelper/WxPayPubHelper.php"); //使用统一支付接口 $unifiedOrder = new UnifiedOrder_pub(); //设置统一支付接口参数 //设置必填参数 //appid已填,商户无需重复填写 //mch_id已填,商户无需重复填写 /

Java微信公众平台开发之OAuth2.0网页授权

根据官方文档点击查看在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的"开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息"的配置选项中,修改授权回调域名.请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头,也不需要加具体的项目名,在域名空间的根目录放一个txt文件才能验证通过一.两种scope授权方式 以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静

微信公众号开发之VS远程调试

前言 微信公众平台消息接口的工作原理大概可以这样理解:从用户端到公众号端一个流程是这样的,用户发送消息到微信服务器,微信服务器将接收到的消息post到用户接入时填写的url中,在url处理程序中,首先判断消息的合法性,判断成功后根据消息体的内容做相应的相应.原理很容易理解,接触过socket的可能理解起来更容易. 其实微信开发并不是很麻烦或者很难,官方给的文档也还算过的去(至少比微信支付的文档好上百倍),最让人痛苦的就是调试,因为微信开发的过程中,用户接收微信发送过来的消息的处理程序对于微信来说

微信公众号开发之LBS

百度地图Web服务api:http://lbsyun.baidu.com/index.php?title=webapi 1.测距 Route Matrix API v2.0:http://lbsyun.baidu.com/index.php?title=webapi/route-matrix-api-v2 1 case "location"://地理位置信息 2 $location_X = $postObj->Location_X; 3 $location_Y = $postOb

微信公众平台开发之emoji表情的使用

关于表情的各种符号代码,参照柳老师的博客:http://blog.csdn.net/lyq8479/article/details/9229631 这里只介绍简单的使用方法. 我们以一个微笑的表情来看,它的表达式有三种: [微笑] 2. /微笑 3. /::) 在CoreService核心类中加入代码测试: public class CoreService {    public static String processRequest(Map<String, String> requestM

微信公众账号开发教程

微信公众账号开发教程 一.第1篇-引言 本文转载来自柳峰老师的博客,在这里非常感谢柳峰老师的分享和贡献! 内容方面,大概会涉及到: 1)前沿知识:微信公众帐号的分类.两种模式各自的特点和区别.开发模式的配置使用等: 2)API中各类消息的使用(我已经对api进行封装并打成了jar包,到时候会考虑分享出来): 3)微信公众帐号开发中的小技巧(如换行.通过代码发送表情.屏幕飘雪花.表情的接收识别.在Android和iOS上表现不一致等等): 4)与业务系统对接的方法(链接.短信等,除了技术讲解还会做

你创建微信公众账号了吗?别闲着,来做微信营销吧

微信占领了我们的生活,微信改变了我们的生活.公交车上刷微信,马桶上在刷微信,边吃饭边刷微信,工作一会儿就刷微信,甚至和朋友吃饭聚会也在刷微信,睡觉前的最后一个动作也在刷微信... 可见,微信现在占据了人们生活的很大一部分,而我们怎么能错过这个商机呢?新的营销时代,微信营销! 想了解微信公众平台管理系统吗http://chenxin.imicro.cc/  爱微imicro微信公众平台管理系统,出售整套系统,包安装,建立和微企一样的平台,拥有属于你自己的站,你也可以给别人开代理账户,自己去运营赚钱

中国大学怎么毁了中国大学生 我对大学有话要说 欢迎大家参与 微信公众账号Lyg5788

中国大学怎么回了中国大学生    我对大学有话要说 为应大家参与  微信公众账号Lyg5788 本文为天慧广告公司原创   微信公众账号Lyg5788 当大学成为消灭童年.浪费青春.消磨斗志.回报渺茫的人生圈套,知识就无力改变个人命运:当大学成为官场.商场.欢场与名利场,大学的谎言就毁了中国精英的生长土壤--可敬的大学,就成了可怕的大学. 校长官员化.行政官僚化.评估泡沫化.建筑浮夸化.人际厚黑化.排名黑幕化.资源集权化.招生产业化.扩张盲目化.文凭贬值化.财政腐败化.监督无力化.授课形式化.学