热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

微信公众平台SDK过程详解

由于本人用的还是NOKIA-C5,没用过微信,对微信的了解肯定没你多,但公司有需求,只好硬着头皮直接看接口文档了。看后发现也挺有意思的,一个很有用的作用就是,当用户给公众账号发消息时,程序可以根据用户发的内容自动回复用户,比如给一个物流公司的公众账号发个运单号,对方自动回复你这个运单号的物流详细,感觉挺酷!
服务号说明:给企业和组织提供更强大的业务服务与用户管理能力,帮助企业快速实现全新的公众号服务平台。

.NETSDK: Loogn.WeiXinSDK (net2.0源码,下面代码只是大概,不太正确,请自行下载源码)

由于本人用的还是NOKIA-C5,没用过微信,对微信的了解肯定没你多,但公司有需求,只好硬着头皮直接看接口文档了。

看后发现也挺有意思的,一个很有用的作用就是,当用户给公众账号发消息时,程序可以根据用户发的内容自动回复用户,比如给一个物流公司的公众账号发个运单号,

对方自动回复你这个运单号的物流详细,感觉挺酷!为了说明方便,先给出申请好的公众账号信息:

现在消息的流程基本清楚了,调用SDK回复消息如下:

using System.Web;using Loogn.WeiXinSDK;using Loogn.WeiXinSDK.Message;namespace WebTest
{    /// 
    /// 微信->服务器配置URL    /// 
    public class WeiXinAPI : IHttpHandler
    {        static string Token = "Token";//这里是Token不是Access_Token
        public void ProcessRequest(HttpContext context)
        {
            context.Response.COntentType= "text/plain";            var signature = context.Request["signature"];            var timestamp = context.Request["timestamp"];            var nOnce= context.Request["nonce"];            if (WeiXin.CheckSignature(signature, timestamp, nonce, Token))//验证是微信给你发的消息            {                //根据注册的消息、事件处理程序回复,                //如果得到没用注册的消息或事件,会返回ReplyEmptyMsg.Instance,即GetXML()为string.Empty,符合微信的要求
                var replyMsg = WeiXin.ReplyMsg();                var xml = replyMsg.GetXML();                //WriteLog(xml); //这里可以查看回复的XML消息                context.Response.Write(xml);
            }            else
            {
                context.Response.Write("fuck you!");
            }
        }        static WeiXinAPI()
        {
            WeiXin.ConfigGlobalCredential("appid", "appSecret");            //注册一个消息处理程序,当用户发"ABC",你回复“你说:ABC”;
            WeiXin.RegisterMsgHandler((msg) =>
            {                return new ReplyTextMsg
                {
                    COntent= "你说:" + msg.Content                    //FromUserName = msg.ToUserName,  默认就是这样,不用设置!                    //ToUserName = msg.FromUserName,  默认就是这样,不用设置!                    //CreateTime = DateTime.Now.Ticks     默认就是这样,不用设置!                };
            });            //注册一个用户关注的事件处理程序,当用户关注你的公众账号时,你回复“Hello!”
            WeiXin.RegisterEventHandler((msg) =>
            {                return new ReplyTextMsg
                {
                    COntent= "Hello !"
                };
            });            //还可以继续注册你感兴趣的消息、事件处理程序        }        public bool IsReusable
        {            get
            {                return false;
            }
        }
    }
}

SDK包含了除(OAuth2.0网页授权)的所有接口的封装,类名及方法名都很明显,这里就不一一演示,有兴趣的朋友可以下载dll自行测试,这是一张付费认证过的接口图:

接下来谈谈实现的几个细节:

一、凭据(access_token)过期

“access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效。公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在开发模式中获得(需要已经成为开发者,且帐号没有异常状态)。”

根据文档上说的,我们可以想到用缓存(不可能每次用每次取吧!),缓存代码是很简单的,主要是在这种情况下要能想到用缓存,下面是非完整代码:

 
       access_token { ;  
         
          expires_in { ;  Dictionary<, Credential> creds =  Dictionary<, Credential>  TokenUrl =   Credential GetCredential( appId, =  (creds.TryGetValue(appId,  (cred.add_time.AddSeconds(cred.expires_in - ) <=  json = Util.HttpGet2(= Util.JsonTo

二、错误码信息

上面说到得到凭据的代码不完整就是因为没有处理可能返回的错误码,微信错误码以json格式返回,如:

{"errcode":40013,"errmsg":"invalid appid"}

大部分由我们主动调用的接口都有可能返回错误码,错误码格式与正常返回的数据格式完全不一样,在SDK里,我是这样处理的,先定义好错误码的模型类,我这里叫ReturnCode,是因为错误码里还包含一个{"errcode":0,"errmsg":"ok"}的请求成功的情况:

       errcode { ;   errmsg { ;     + errcode +  + errmsg +

定义有错误码的返回消息类时我们就可以包含一个ReturnCode类型的属性了,如创建二维码接口:

    public class QRCodeTicket
    {        public string ticket { get; set; }        public int expire_seconds { get; set; }        public ReturnCode error { get; set; }
    }

从返回的json到QRCodeTicket对象的代码大概就是这样(其他的也是类似):

            var json = Util.HttpPost2(url, data);            if (json.IndexOf("ticket") > 0)
            {                return Util.JsonTo(json);
            }            else
            {
                QRCodeTicket tk = new QRCodeTicket();
                tk.error = Util.JsonTo(json);                return tk;
            }

所以用SDK调用接口后,得到的对象就可轻松判断了:

            var qrcode = WeiXin.CreateQRCode(true, 23);            if (qrcode.error == null)
            {                //返回错误,可以用qrcode.error查看错误消息            }            else
            { 
                //返回正确,可以操作qrcode.ticket
            }

三、反序列化

微信接口返回的json有时候对我们映射到对象并不太直接(json格式太灵活了!),比如创建分组成功后返回的json:

{    "group": {        "id": 107, 
        "name": "test"
    }
}

如果想直接用json通过反序列化得到对象,那么这个对象的类的定义有可能会是这样:

    public class GroupInfo
    {        public Group group { get; set; }        public class Group
        {            public int id { get; set; }            public string name { get; set; }
        }
    }

访问的时候也会是gp.group.name,所以我说不太直接,我们想要的类的定义肯定是只有上面那个子类的样子:

    public class GroupInfo
    {            public int id { get; set; }            public string name { get; set; }
    }

如果微信接口返回的是这样:

    {        "id": 107, 
        "name": "test"
    }

就再好不过了,但人家的代码,我们修改不了,我们只有自己想办法.

1,要简单类,2不手动分析json(如正则),3,不想多定义一个类,你有想到很好的方法吗?如果有可以回复给我,而我选择用字典来做中间转换。

因为基本所有的json格式都可以反序列化为字典(嵌套字典,嵌套字典集合等),比如上面微信返回的json就可以用以下的类型来表示:

Dictionary>

json--->dict--->GroupInfo

var dict = Util.JsonTo>>(json);var gi = new GroupInfo();var gpdict = dict["group"];
gi.id = Convert.ToInt32(gpdict["id"]);
gi.name = gpdict["name"].ToString();

四、消息处理的优化

"万物简单为美",我就是一个非常非常喜欢简单的程序员。还记得最开始的那个消息(事件属于消息,这里统称为消息)处理吧,我感觉是很简单的,需要处理哪个消息就注册哪个消息的处理程序。但一开始的时候不是这样的,开始的时候要手动判断消息类型,就像:

using System.Web;using Loogn.WeiXinSDK;using Loogn.WeiXinSDK.Message;namespace WebTest
{    /// 
    /// 微信->服务器配置URL    /// 
    public class WeiXinAPI : IHttpHandler
    {        static string Token = "Token";//这里是Token不是Access_Token
        public void ProcessRequest(HttpContext context)
        {
            context.Response.COntentType= "text/plain";            var signature = context.Request["signature"];            var timestamp = context.Request["timestamp"];            var nOnce= context.Request["nonce"];            if (WeiXin.CheckSignature(signature, timestamp, nonce, Token))//验证是微信给你发的消息            {                var replyMsg = WeiXin.ReplyMsg((recEvtMsg) =>
                {                    switch (recEvtMsg.MsgType)
                    {                        case MsgType.text:
                            {                                var msg = recEvtMsg as RecTextMsg; //这里要转型,麻烦
                                return new ReplyTextMsg
                                {
                                    COntent= "你说:" + msg.Content
                                };
                            }                        case MsgType.Event:
                            {                                var evtMsg = recEvtMsg as EventBaseMsg;//这里要转型到事件消息的基本,麻烦
                                switch (evtMsg.MyEventType)
                                {                                    case MyEventType.Attend:                                        var msg = evtMsg as EventAttendMsg;//这个例子不需要这行代码,但其他要用消息内容还是要转型,麻烦
                                        return new ReplyTextMsg
                                        {
                                            COntent= "Hello !"
                                        };                                        
                                    default:                                        break;
                                }                                break;
                            }                        default:                            break;
                    }                    return ReplyEmptyMsg.Instance;                    //嵌套switch,而且每个case都有好几个,这也不优雅                });                var xml = replyMsg.GetXML();                //WriteLog(xml); //这里可以查看回复的XML消息                context.Response.Write(xml);
            }            else
            {
                context.Response.Write("fuck you!");
            }
        }        public bool IsReusable
        {            get
            {                return false;
            }
        }
    }
}

做优化的时候,先是试着看能不能在MsgType和MyEventType上做文章,比如注册时传入MsgType和处理程序(lamba)两个参数:

public static void RegisterMsgHandler(MsgType type, Func handler)
{    //add handler}

这样的确是可以行的通的,但是在调用SDK注册的时候还是要手动转换类型:

 WeiXin.RegisterMsgHandler(MsgType.text, (recEvtMsg) => msg = recEvtMsg   ReplyTextMsg { COntent=  +

那么能不能每个子类型写一个呢?

    public static void RegisterMsgHandler(MsgType type, Func handler)
    {        //add handler    }    public static void RegisterMsgHandler(MsgType type, Func handler)
    {        //add handler    }    //.............

定义是可以的,来看看调用:

//可以RegisterMsgHandler(MsgType.text, new Func((msg) =>{    return new ReplyTextMsg { COntent= "你说:" + msg.Content };
}));//可以RegisterMsgHandler(MsgType.text, new Func((msg) =>{    return new ReplyTextMsg { COntent= "你发的图片:" + msg.PicUrl };
}));//可以,注意这里msg的智能提示是RecTextMsg类型RegisterMsgHandler(MsgType.text, (msg) =>{    return new ReplyTextMsg { COntent= "你说:" +msg.Content};
});//可以,注意这里msg的智能提示还是RecTextMsg类型,但用了类型推断,运行时可以确定是RecImageMsg,所以可以RegisterMsgHandler(MsgType.text, (msg) =>{    return new ReplyTextMsg { COntent= "你发的图片:" + msg.PicUrl };
});//不可以,注意这里msg的智能提示还是RecTextMsg类型,但lamba body里没有用msg的特定子类的属性,类型推断不了,所以调用不明RegisterMsgHandler(MsgType.text, (msg) =>{    return new ReplyTextMsg { COntent= "你发了个消息" };
});

从上面调用可知,想用这种方法调用,就不能随意的用lamba表达式,我所不欲也!最后,终于用泛型搞定了

public static void RegisterMsgHandler(Func handler) where TMsg : RecBaseMsg
        {            var type = typeof(TMsg);            var key = string.Empty;            if (type == typeof(RecTextMsg))
            {
                key = MsgType.text.ToString();
            }            else if (type == typeof(RecImageMsg))
            {
                key = MsgType.image.ToString();
            }            else if (type == typeof(RecLinkMsg))
            {
                key = MsgType.link.ToString();
            }            else if (type == typeof(RecLocationMsg))
            {
                key = MsgType.location.ToString();
            }            else if (type == typeof(RecVideoMsg))
            {
                key = MsgType.video.ToString();
            }            else if (type == typeof(RecVoiceMsg))
            {
                key = MsgType.voice.ToString();
            }            else
            {                return;
            }
            m_msgHandlers[key] = (Func)handler;
        }

经过这样的变换,我们才可以像开始那样用简洁的lamba表达式注册。

以上就是微信公众平台SDK过程详解的详细内容,更多请关注php中文网其它相关文章!


推荐阅读
  • PHPcURL获取微信公众号access_token的实例php实例:这篇文章主要介绍了PHPcURL获取微信公众号access_token的实例,需要的朋友可以参考下1.开发微信 ... [详细]
  • CentOS8.4 安装PHP7.4.25
    1、下载官网:https:www.php.netdownloads#cdmydata#wgethttps:www.php.netdistributionsphp ... [详细]
  • crossorigin注解添加了解决不了跨域问题_CORS与@CrossOrigin详解
    1、跨域的基本概念a、跨域的解释要了解跨域,首先需要知晓浏览器的同源策略,简单的说就是两个请求协议、端口、主机都相同,则两个请求具有相同的 ... [详细]
  • spring-session解决session一致性问题,Go语言社区,Golang程序员人脉社 ... [详细]
  • jquery popupDialog 使用 加载jsp页面办法
    php教程|PHP开发jqueryphp教程-PHP开发如下所示:软件市场源码,vsCode字体不变,ubuntu的所有版本,taotomcat,sqlite连接php,个人域名服 ... [详细]
  • Linux是一套免费使用和***传播的类UNIX操作系统,主要用于基于Intel x86系列CPU的计算机上。Linux系统是由全世界各地的成千上万的程序员合适的方式定制自己的Li ... [详细]
  • 以下内容|尾部_quarkus实战之一:准备工作
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了quarkus实战之一:准备工作相关的知识,希望对你有一定的参考价值。欢迎访问我的GitHub ... [详细]
  • 事务是通过MULTI命令开始的,在非事务状态下客户端发送的命令会被立刻执行,而在事务状态下,除了EXECWATCHDISCARD这几个命令外,redis会将命令保留在事务队列里。 ... [详细]
  •   uni-app开发教程,uni-app实例教程  UNI-APP开发(仿饿)开发课程:进入学习  推荐(免费):uni-app开发教程  文章目录  简介,网 ... [详细]
  • 导读:今天编程笔记来给各位分享关于php动态扩展怎么加载的相关内容,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览: ... [详细]
  • 大数据分析Python有哪些爬虫框架
    一、ScrapyScrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。。用 ... [详细]
  • nvmw安装,用于控制node版本;
    之前一直使用的是nodev2.2.0版本,挺说新版本的node解决了npm安装插件产生文件夹结构过深的问题,所以就想更新试试;上网一看才发现,尼玛的node已经到了6.+版本了,好 ... [详细]
  • 有不少人向我抱怨说工作中都是写业务代码,刚开始还有新鲜感,熟练了以后就觉得无聊了。这样的问题多了,也促使我去思考和总结,我总 ... [详细]
  • 7月9日结束了我的小学期后,正式开始了我的假期生活。这个星期,初步了解了一些Java的基础知识。1.JDK顾名思义是java开发工具包,是程序员使用java语言编写java程序所需 ... [详细]
  • 超赞!GitHub上百万下载量Java面试手册!颠覆你的认知
    金三面试不顺心,马上银四面试在即,自己复盘总觉得Java知识点很凌乱?没有合适的方法学习!今天分享这份GitHub上百万下载量Ja ... [详细]
author-avatar
mobiledu2502926037
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有