Maison  >  Article  >  Applet WeChat  >  Explication détaillée du processus SDK de la plateforme publique WeChat

Explication détaillée du processus SDK de la plateforme publique WeChat

Y2J
Y2Joriginal
2017-04-27 13:49:073487parcourir

Description du compte de service : fournissez aux entreprises et aux organisations des services commerciaux et des capacités de gestion des utilisateurs plus puissants, et aidez les entreprises à mettre en œuvre rapidement une nouvelle plate-forme de services de compte public.

.NETSDK : Loogn.WeiXinSDK (code source net2.0, le code suivant n'est qu'approximatif et pas très correct, veuillez télécharger le code source vous-même)

Puisque j'utilise toujours NOKIA-C5 , je ne l'ai jamais utilisé. WeChat, je n'en sais certainement pas autant que vous sur WeChat, mais l'entreprise a des besoins, je dois donc serrer les dents et lire directement la documentation de l'interface.

Après l'avoir lu, je l'ai trouvé assez intéressant. Une fonction très utile est que lorsqu'un utilisateur envoie un message à un compte public, le programme peut répondre automatiquement à l'utilisateur en fonction du contenu envoyé par l'utilisateur, comme l'envoi d'un message sur le compte public d'une entreprise de logistique. Un numéro de lettre de transport,

L'autre partie vous répondra automatiquement avec les détails logistiques de ce numéro de lettre de transport, ce qui est plutôt cool ! Pour faciliter l'explication, les informations du compte public appliquées sont d'abord données :

La figure suivante montre le processus de message détaillé de visualisation de la logistique ci-dessus (les chiffres dans les lignes pointillées indiquez l'ordre du processus) :

WeChat enverra deux principaux types de messages à votre URL :

L'un est le message général de l'utilisateur, tel que le numéro de lettre de voiture envoyé par l'utilisateur ci-dessus ;

Le second est le comportement de l'utilisateur (c'est-à-dire les événements mentionnés dans le document), comme l'utilisateur qui suit votre compte public, scanne le code QR du compte public, clique sur sur votre menu personnalisé, etc.

Votre URL peut répondre en fonction du type et du contenu du message reçu pour obtenir des services commerciaux puissants, tels que les détails logistiques renvoyés ci-dessus. Tous les messages sont transmis au format XML et le SDK convertit le XML en objets .NET pour vous faciliter l'écriture de la logique métier. Le diagramme de classes framework du message est représenté comme (cliquez pour voir le diagramme complet incluant les sous-classes) :

Il y a d'abord une classe de base de message, puis le message reçu (RecEventBaseMsg ) et message de réponse (ReplyBaseMsg), comme mentionné ci-dessus, le message reçu est divisé en deux catégories, à savoir le message général (RecBaseMsg) et le message d'événement (EventBaseMsg). Le type de message reçu peut être représenté par une énumération :

Sans parler des autres types, lorsque MsgType est Event, le message est une sous-classe de EventBaseMsg. Le MsgType de toutes les sous-classes de EventBaseMsg est Event, donc le type EventBaseMsg a également un EventType pour distinguer les différents. événements, si vous avez lu le document d'interface, sachez que son type d'événement n'est pas très convivial pour que nous puissions déterminer de quel événement il s'agit. L'événement de numérisation du code QR se divise en deux situations : l'utilisateur a prêté attention et l'utilisateur a prêté attention. pas prêté attention. Lors du suivi, le EventType est analysé, lorsqu'il ne suit pas, le EventType est s'abonner, et le EventType de l'événement que l'utilisateur suit est également s'abonner, donc un autre MyEventType est ajouté au SDK :

Maintenant, le flux des messages est fondamentalement clair. Le message de réponse lors de l'appel du SDK est le suivant :

using System.Web;using Loogn.WeiXinSDK;using Loogn.WeiXinSDK.Message;namespace WebTest
{    /// <summary>
    /// 微信->服务器配置URL    /// </summary>
    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<RecTextMsg>((msg) =>
            {                return new ReplyTextMsg
                {
                    Content = "你说:" + msg.Content                    //FromUserName = msg.ToUserName,  默认就是这样,不用设置!                    //ToUserName = msg.FromUserName,  默认就是这样,不用设置!                    //CreateTime = DateTime.Now.Ticks     默认就是这样,不用设置!                };
            });            //注册一个用户关注的事件处理程序,当用户关注你的公众账号时,你回复“Hello!”
            WeiXin.RegisterEventHandler<EventAttendMsg>((msg) =>
            {                return new ReplyTextMsg
                {
                    Content = "Hello !"
                };
            });            //还可以继续注册你感兴趣的消息、事件处理程序        }        public bool IsReusable
        {            get
            {                return false;
            }
        }
    }
}
Le SDK contient l'encapsulation de toutes les interfaces sauf (OAuth2.0). autorisation web). Les noms de classe et les noms de méthodes sont très évidents, je ne les listerai donc pas un par un ici Démonstration, les amis intéressés peuvent télécharger la dll et la tester par eux-mêmes. Il s'agit d'un schéma d'interface payant et certifié : <.>

Parlons de quelques détails de la mise en œuvre :

1. Expiration des informations d'identification (access_token)

« access_token est le ticket unique au monde. du compte officiel. Le compte officiel doit utiliser access_token lors de l'appel de chaque interface. Dans des circonstances normales

access_token est valide pendant 7 200 secondes

, une acquisition répétée rendra le dernier access_token invalide. et AppSecret pour appeler cette interface pour obtenir access_token. AppID et AppSecret peuvent être obtenus en mode développement (vous devez être développeur et le compte n'a pas de statut anormal ”D'après la documentation, nous pouvons). pensez à utiliser la mise en cache (c'est impossible de l'utiliser à chaque fois !). La mise en cache du code est très simple, principalement dans

ce cas, je peux penser à

utiliser la mise en cache. > code : 2. Informations sur le code d'erreur

Le code mentionné ci-dessus pour obtenir les informations d'identification est incomplet. Parce que les codes d'erreur qui peuvent être renvoyés ne sont pas traités, les codes d'erreur WeChat sont renvoyés. au format json, tel que :
 
       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<Credential>

La plupart des interfaces que nous appelons activement peuvent renvoyer des codes d'erreur, et le format du code d'erreur est le même que celui renvoyé normalement. Le format des données est complètement différent dans le. SDK, je le gère comme ceci. Définissez d'abord la classe de modèle du code d'erreur. Je l'appelle ReturnCode car le code d'erreur contient également {"errcode":0,"errmsg":" ok"} la requête est réussie :

{"errcode":40013,"errmsg":"invalid appid"}
Lors de la définition d'une classe de message de retour avec un code d'erreur, nous pouvons inclure un attribut de type ReturnCode, comme par exemple créer une interface de code QR :

       errcode { ;   errmsg { ;     + errcode +  + errmsg +
Le code du json retourné au L'objet QRCodeTicket est probablement comme ceci (d'autres sont similaires) :

    public class QRCodeTicket
    {        public string ticket { get; set; }        public int expire_seconds { get; set; }        public ReturnCode error { get; set; }
    }
Ainsi, après avoir appelé l'interface avec le SDK, l'objet obtenu peut être facilement jugé :

            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<string, Dictionary<string, object>>

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
{    /// <summary>
    /// 微信->服务器配置URL    /// </summary>
    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<RecEventBaseMsg, ReplyBaseMsg> handler)
{    //add handler}

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

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

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

    public static void RegisterMsgHandler(MsgType type, Func<RecTextMsg, ReplyBaseMsg> handler)
    {        //add handler    }    public static void RegisterMsgHandler(MsgType type, Func<RecImageMsg, ReplyBaseMsg> handler)
    {        //add handler    }    //.............

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

//可以RegisterMsgHandler(MsgType.text, new Func<RecTextMsg, ReplyBaseMsg>((msg) =>{    return new ReplyTextMsg { Content = "你说:" + msg.Content };
}));//可以RegisterMsgHandler(MsgType.text, new Func<RecImageMsg, ReplyBaseMsg>((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<TMsg>(Func<TMsg, ReplyBaseMsg> 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<RecEventBaseMsg, ReplyBaseMsg>)handler;
        }

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn