溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

微信公眾平臺SDK過程的示例分析

發(fā)布時間:2021-09-13 17:25:46 來源:億速云 閱讀:126 作者:小新 欄目:移動開發(fā)

小編給大家分享一下微信公眾平臺SDK過程的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

服務(wù)號說明:給企業(yè)和組織提供更強大的業(yè)務(wù)服務(wù)與用戶管理能力,幫助企業(yè)快速實現(xiàn)全新的公眾號服務(wù)平臺。

.NETSDK: Loogn.WeiXinSDK (net2.0源碼,下面代碼只是大概,不太正確,請自行下載源碼)

由于本人用的還是NOKIA-C5,沒用過微信,對微信的了解肯定沒你多,但公司有需求,只好硬著頭皮直接看接口文檔了。

看后發(fā)現(xiàn)也挺有意思的,一個很有用的作用就是,當(dāng)用戶給公眾賬號發(fā)消息時,程序可以根據(jù)用戶發(fā)的內(nèi)容自動回復(fù)用戶,比如給一個物流公司的公眾賬號發(fā)個運單號,

對方自動回復(fù)你這個運單號的物流詳細(xì),感覺挺酷!為了說明方便,先給出申請好的公眾賬號信息:

微信公眾平臺SDK過程的示例分析

下圖為表示上面查看物流詳細(xì)的消息流程(虛線的編號表示流程的順序):

微信公眾平臺SDK過程的示例分析

微信會向你的URL發(fā)送兩大類消息:

一是用戶的一般消息,如上面用戶發(fā)的運單號;

二是用戶的行為(即文檔中說的事件)  ,如用戶關(guān)注了你的公眾賬號、掃描了公眾賬號的二維碼、點擊了你自定義的菜單等。

你的URL就可以根據(jù)收到的消息類型和內(nèi)容做出回應(yīng)以實現(xiàn)強大的業(yè)務(wù)服務(wù),如上面返回的物流詳細(xì)。消息全部是以XML格式傳遞,而SDK做的就是把XML轉(zhuǎn)換成.NET對象,以方便你編寫業(yè)務(wù)邏輯。消息的框架類圖表示為(點擊查看包括子類的全圖):

微信公眾平臺SDK過程的示例分析

首先有個消息基類,然后是收到的消息(RecEventBaseMsg)和回復(fù)的消息(ReplyBaseMsg),上面說了,收到的消息分兩大類,即一般消息(RecBaseMsg)和事件消息(EventBaseMsg),收到的消息類型用枚舉表示可以是:

微信公眾平臺SDK過程的示例分析

其他的類型不說,而當(dāng)MsgType為Event時,消息便是EventBaseMsg的子類了,所有EventBaseMsg的子類的MsgType都是Event,所以EventBaseMsg類型又有個EventType來區(qū)分不同的事件,如果你看過接口文檔,你應(yīng)該知道,它的事件類型對我們判斷到底是哪個事件不太友好,掃描二維碼事件分了用戶已關(guān)注和未關(guān)注兩種情況,已關(guān)注時EvenType是scan,未關(guān)注時EventType是subscribe,而用戶關(guān)注事件的EventType也是subscribe,所以SDK里又加了個MyEventType:

微信公眾平臺SDK過程的示例分析

現(xiàn)在消息的流程基本清楚了,調(diào)用SDK回復(fù)消息如下:

using System.Web;using Loogn.WeiXinSDK;using Loogn.WeiXinSDK.Message;namespace WebTest
{    /// <summary>
    /// 微信->服務(wù)器配置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))//驗證是微信給你發(fā)的消息            {                //根據(jù)注冊的消息、事件處理程序回復(fù),                //如果得到?jīng)]用注冊的消息或事件,會返回ReplyEmptyMsg.Instance,即GetXML()為string.Empty,符合微信的要求
                var replyMsg = WeiXin.ReplyMsg();                var xml = replyMsg.GetXML();                //WriteLog(xml); //這里可以查看回復(fù)的XML消息                context.Response.Write(xml);
            }            else
            {
                context.Response.Write("fuck you!");
            }
        }        static WeiXinAPI()
        {
            WeiXin.ConfigGlobalCredential("appid", "appSecret");            //注冊一個消息處理程序,當(dāng)用戶發(fā)"ABC",你回復(fù)“你說:ABC”;
            WeiXin.RegisterMsgHandler<RecTextMsg>((msg) =>
            {                return new ReplyTextMsg
                {
                    Content = "你說:" + msg.Content                    //FromUserName = msg.ToUserName,  默認(rèn)就是這樣,不用設(shè)置!                    //ToUserName = msg.FromUserName,  默認(rèn)就是這樣,不用設(shè)置!                    //CreateTime = DateTime.Now.Ticks     默認(rèn)就是這樣,不用設(shè)置!                };
            });            //注冊一個用戶關(guān)注的事件處理程序,當(dāng)用戶關(guān)注你的公眾賬號時,你回復(fù)“Hello!”
            WeiXin.RegisterEventHandler<EventAttendMsg>((msg) =>
            {                return new ReplyTextMsg
                {
                    Content = "Hello !"
                };
            });            //還可以繼續(xù)注冊你感興趣的消息、事件處理程序        }        public bool IsReusable
        {            get
            {                return false;
            }
        }
    }
}

SDK包含了除(OAuth3.0網(wǎng)頁授權(quán))的所有接口的封裝,類名及方法名都很明顯,這里就不一一演示,有興趣的朋友可以下載dll自行測試,這是一張付費認(rèn)證過的接口圖:

微信公眾平臺SDK過程的示例分析

接下來談?wù)剬崿F(xiàn)的幾個細(xì)節(jié):

一、憑據(jù)(access_token)過期

“access_token是公眾號的全局唯一票據(jù),公眾號調(diào)用各接口時都需使用access_token。正常情況下access_token有效期為7200秒,重復(fù)獲取將導(dǎo)致上次獲取的access_token失效。公眾號可以使用AppID和AppSecret調(diào)用本接口來獲取access_token。AppID和AppSecret可在開發(fā)模式中獲得(需要已經(jīng)成為開發(fā)者,且?guī)ぬ枦]有異常狀態(tài))?!?/p>

根據(jù)文檔上說的,我們可以想到用緩存(不可能每次用每次取吧?。?緩存代碼是很簡單的,主要是在這種情況下要能想到用緩存,下面是非完整代碼:

 
       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>

二、錯誤碼信息

上面說到得到憑據(jù)的代碼不完整就是因為沒有處理可能返回的錯誤碼,微信錯誤碼以json格式返回,如:

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

大部分由我們主動調(diào)用的接口都有可能返回錯誤碼,錯誤碼格式與正常返回的數(shù)據(jù)格式完全不一樣,在SDK里,我是這樣處理的,先定義好錯誤碼的模型類,我這里叫ReturnCode,是因為錯誤碼里還包含一個{"errcode":0,"errmsg":"ok"}的請求成功的情況:

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

定義有錯誤碼的返回消息類時我們就可以包含一個ReturnCode類型的屬性了,如創(chuàng)建二維碼接口:

    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<QRCodeTicket>(json);
            }            else
            {
                QRCodeTicket tk = new QRCodeTicket();
                tk.error = Util.JsonTo<ReturnCode>(json);                return tk;
            }

所以用SDK調(diào)用接口后,得到的對象就可輕松判斷了:

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

三、反序列化

微信接口返回的json有時候?qū)ξ覀冇成涞綄ο蟛⒉惶苯樱╦son格式太靈活了?。?,比如創(chuàng)建分組成功后返回的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,不想多定義一個類,你有想到很好的方法嗎?如果有可以回復(fù)給我,而我選擇用字典來做中間轉(zhuǎn)換。

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

Dictionary<string, Dictionary<string, object>>

json--->dict--->GroupInfo

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

四、消息處理的優(yōu)化

"萬物簡單為美",我就是一個非常非常喜歡簡單的程序員。還記得最開始的那個消息(事件屬于消息,這里統(tǒng)稱為消息)處理吧,我感覺是很簡單的,需要處理哪個消息就注冊哪個消息的處理程序。但一開始的時候不是這樣的,開始的時候要手動判斷消息類型,就像:

using System.Web;using Loogn.WeiXinSDK;using Loogn.WeiXinSDK.Message;namespace WebTest
{    /// <summary>
    /// 微信->服務(wù)器配置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))//驗證是微信給你發(fā)的消息            {                var replyMsg = WeiXin.ReplyMsg((recEvtMsg) =>
                {                    switch (recEvtMsg.MsgType)
                    {                        case MsgType.text:
                            {                                var msg = recEvtMsg as RecTextMsg; //這里要轉(zhuǎn)型,麻煩
                                return new ReplyTextMsg
                                {
                                    Content = "你說:" + msg.Content
                                };
                            }                        case MsgType.Event:
                            {                                var evtMsg = recEvtMsg as EventBaseMsg;//這里要轉(zhuǎn)型到事件消息的基本,麻煩
                                switch (evtMsg.MyEventType)
                                {                                    case MyEventType.Attend:                                        var msg = evtMsg as EventAttendMsg;//這個例子不需要這行代碼,但其他要用消息內(nèi)容還是要轉(zhuǎn)型,麻煩
                                        return new ReplyTextMsg
                                        {
                                            Content = "Hello !"
                                        };                                        
                                    default:                                        break;
                                }                                break;
                            }                        default:                            break;
                    }                    return ReplyEmptyMsg.Instance;                    //嵌套switch,而且每個case都有好幾個,這也不優(yōu)雅                });                var xml = replyMsg.GetXML();                //WriteLog(xml); //這里可以查看回復(fù)的XML消息                context.Response.Write(xml);
            }            else
            {
                context.Response.Write("fuck you!");
            }
        }        public bool IsReusable
        {            get
            {                return false;
            }
        }
    }
}

做優(yōu)化的時候,先是試著看能不能在MsgType和MyEventType上做文章,比如注冊時傳入MsgType和處理程序(lamba)兩個參數(shù):

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

這樣的確是可以行的通的,但是在調(diào)用SDK注冊的時候還是要手動轉(zhuǎn)換類型:

 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    }    //.............

定義是可以的,來看看調(diào)用:

//可以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 = "你發(fā)的圖片:" + 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 = "你發(fā)的圖片:" + msg.PicUrl };
});//不可以,注意這里msg的智能提示還是RecTextMsg類型,但lamba body里沒有用msg的特定子類的屬性,類型推斷不了,所以調(diào)用不明RegisterMsgHandler(MsgType.text, (msg) =>{    return new ReplyTextMsg { Content = "你發(fā)了個消息" };
});

從上面調(diào)用可知,想用這種方法調(diào)用,就不能隨意的用lamba表達(dá)式,我所不欲也!最后,終于用泛型搞定了

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

經(jīng)過這樣的變換,我們才可以像開始那樣用簡潔的lamba表達(dá)式注冊。

以上是“微信公眾平臺SDK過程的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI