ホームページ  >  記事  >  WeChat アプレット  >  WeChatパブリックプラットフォームSDKプロセスの詳細な説明

WeChatパブリックプラットフォームSDKプロセスの詳細な説明

Y2J
Y2Jオリジナル
2017-04-27 13:49:073424ブラウズ

サービス アカウントの説明: 企業や組織に、より強力なビジネス サービスとユーザー管理機能を提供し、企業が新しいパブリック アカウント サービス プラットフォームを迅速に実装できるように支援します。

.NETSDK: Loogn.WeiXinSDK (net2.0 ソース コード、次のコードはおおよそのものであり、あまり正確ではありません。ソース コードは自分でダウンロードしてください)

私はまだ NOKIA-C5 を使用しており、WeChat を使用したことがないので、 WeChat についてまったく理解していません。あなたにはもっとたくさんのことがありますが、会社にはニーズがあるので、私はしっかりとインターフェイスのドキュメントを読む必要があります。

読んでみて、非常に便利な機能は、ユーザーが公開アカウントにメッセージを送信すると、ユーザーが送信した内容に基づいてプログラムが自動的にユーザーに返信できることです。運送状番号を物流会社の公開アカウントに送信します。

相手はこの運送状番号の物流詳細を自動的に返信します。これは非常にクールです。説明の便宜上、最初に適用された公開アカウント情報を与えます:

以下の図は、上記のロジスティクスを表示する詳細なメッセージプロセスを示しています (点線内の数字はプロセスの順序を示します):

WeChat から送信される URL は、主に 2 種類のメッセージです。

1 つ目は、上記のユーザーが送信した運送状番号などのユーザーの一般的なメッセージです

2 つ目は、ユーザーの行動 (つまり、イベント)ユーザーがあなたの公開アカウントをフォローした、公開アカウントの QR コードをスキャンした、カスタマイズされたメニューをクリックしたなど)。

URL は、受信した メッセージ タイプとコンテンツ に基づいて応答し、上記で返された物流の詳細などの強力なビジネス サービスを実現できます。すべてのメッセージは XML 形式で配信され、SDK は XML を .NET オブジェクトに変換して、ビジネス ロジックの作成を容易にします。メッセージのフレームワーク クラス図は次のように表されます (クリックすると、サブクラスを含む全体図が表示されます):

最初にメッセージの基本クラスがあり、次に受信メッセージ (RecEventBaseMsg) と応答メッセージ (ReplyBaseMsg) があります。上で説明したように、受信メッセージは、一般メッセージ (RecBaseMsg) とイベント メッセージ (EventBaseMsg) の 2 つのカテゴリに分類されます。受信メッセージのタイプは列挙によって表すことができます。他のタイプは言及されていません。MsgType が指定されている場合は、 Event、メッセージは EventBaseMsg のサブクラスです。すべての EventBaseMsg サブクラスの MsgType は Event です。したがって、EventBaseMsg タイプには、さまざまなイベントを区別するための EventType もあります。そのイベントのタイプは ではないことがわかります。 QR コードのスキャン イベントは、ユーザーがフォローしている場合とフォローしていない場合の 2 つの状況に分けられます。ユーザーがイベントをフォローしている場合、EventType はスキャンです。注目していないため、EventType は購読であり、ユーザーがフォローしたイベントの EventType も購読であるため、別の MyEventType が SDK に追加されました:

これで、返信するための SDK の呼び出しプロセスは基本的に明確になりました。メッセージは次のとおりです:

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;
            }
        }
    }
}

SDK には (OAuth2.0 Web 認証) を除くすべてのインターフェイスのカプセル化が含まれています。クラス名とメソッド名は非常に明白なので、ここでは 1 つずつ説明しません。 DLL をダウンロードして自分でテストできます。これは有料の認定済みインターフェイス図です:

次に、いくつかの実装について説明します:

1. 資格情報 (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<Credential>

2. エラー コード情報 前述したように、WeChat エラー コードは次のような json 形式で返されるため、認証情報を取得するコードは不完全です。エラーコードの形式は、通常返されるデータ形式とはまったく異なります。まず、呼び出すエラーコードのモデルクラスを定義します。リクエストが成功したときの {"errcode":0,"errmsg":"ok"} 状況も含まれているため、ここに ReturnCode を記述します:

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

エラー コードを含むリターン メッセージ クラスを定義する場合、二次元の Code インターフェイスを作成するなど、ReturnCode タイプの属性を含めることができます:

       errcode { ;   errmsg { ;     + errcode +  + errmsg +
返された json から QRCodeTicket オブジェクトへのコードはおそらく次のようになります (他のコードも同様です):
    public class QRCodeTicket
    {        public string ticket { get; set; }        public int expire_seconds { get; set; }        public ReturnCode error { get; set; }
    }
So を呼び出した後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<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表达式注册。

以上がWeChatパブリックプラットフォームSDKプロセスの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。