国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
追蹤/取消追蹤事件
掃描帶參數(shù)二維碼事件
上報地理位置事件
首頁 微信小程式 微信開發(fā) 微信開發(fā)之接收事件推播與訊息排重

微信開發(fā)之接收事件推播與訊息排重

May 09, 2017 am 09:39 AM

在上一篇的博文中講到,微信的訊息可以大體分為兩種類型,一種是包括:文本,語音,圖片等的普通訊息,另一種就是本篇要將的事件類型。包括:追蹤/取消關(guān)注事件,掃描帶參數(shù)二維碼事件,上報地理位置事件,自訂選單相關(guān)事件等。本篇一一進(jìn)行講解。

上一篇也提到了,微信伺服器在5秒內(nèi)收不到回應(yīng)會斷掉連接,並且重新發(fā)起請求,總共重試三次。 這樣的話,問題就來了。有這樣一個場景:當(dāng)用戶關(guān)注微信帳號時,獲取當(dāng)前用戶信息,然後將信息寫到資料庫中。類似pc端網(wǎng)站的註冊??赡苡伸哆@個關(guān)注事件中,我們需要處理的業(yè)務(wù)邏輯比較複雜。如送積分啊,寫用戶日誌啊,分配用戶群組啊。等等……一系列的邏輯需要執(zhí)行,或者網(wǎng)路環(huán)境比較複雜,無法保證5秒內(nèi)回應(yīng)當(dāng)前用戶的操作,那如果當(dāng)操作尚未完成,微信伺服器又給我們的伺服器推送了一條相同的關(guān)注事件,我們將再次執(zhí)行我們的那些邏輯,這樣就有可能導(dǎo)致資料庫中出現(xiàn)重複的資料(有的童鞋就會說了,我在插入資料之前先判斷目前是否已經(jīng)存在了,如果存在了就不執(zhí)行插入的操作。 我想說的是,我當(dāng)初也是這樣想的,但真實的運(yùn)行環(huán)境和我們的調(diào)試環(huán)境還是有差距的,直到發(fā)現(xiàn)數(shù)據(jù)庫中有不少重複的用戶資訊時,我才發(fā)現(xiàn)消息去重的重要性。

訊息的去重普通訊息和事件訊息是有區(qū)別的。普通訊息使用msgid,而事件訊息使用FromUserName + CreateTime。我的想法是:

  1. 新類別BaseMsg,有三個屬性分別是FromUser,MsgFlag,CreateTime。程式碼如下:

  2. public class BaseMsg
        {        /// <summary>
            /// 發(fā)送者標(biāo)識        /// </summary>
            public string FromUser { get; set; }        /// <summary>
            /// 消息表示。普通消息時,為msgid,事件消息時,為事件的創(chuàng)建時間        /// </summary>
            public string MsgFlag { get; set; }        /// <summary>
            /// 添加到隊列的時間        /// </summary>
            public DateTime CreateTime { get; set; }
        }
  3. 建立個靜態(tài)列表_queue,用來儲存訊息列表,列表的型別是List.

  4. 在處理微信訊息體前,先判斷列表是否實例化,如果沒有實例化則實例化,否則判斷列表的長度是否大於或等於50(這個可以自定義,用處就是微信並發(fā)的訊息量),如果大於或等於50,則保留20秒內(nèi)未回應(yīng)的訊息(5秒重試一次,總共重試3次,就是15秒,保險起見這裡寫20秒)。

  5. 取得目前訊息體的訊息類型,並根據(jù)_queue判斷目前訊息是否已經(jīng)要求了。如果是事件則儲存FromUser和建立時間。如果是普通訊息則儲存MsgFlag。下面是程式碼:

if (_queue == null)
            {
                _queue = new List<BaseMsg>();
            }            else if(_queue.Count>=50)
            {
                _queue = _queue.Where(q => { return q.CreateTime.AddSeconds(20) > DateTime.Now; }).ToList();//保留20秒內(nèi)未響應(yīng)的消息            }
            XElement xdoc = XElement.Parse(xml);            var msgtype = xdoc.Element("MsgType").Value.ToUpper();            var FromUserName = xdoc.Element("FromUserName").Value;            var MsgId = xdoc.Element("MsgId").Value;            var CreateTime = xdoc.Element("CreateTime").Value;
            MsgType type = (MsgType)Enum.Parse(typeof(MsgType), msgtype);            if (type!=MsgType.EVENT)
            {                if (_queue.FirstOrDefault(m => { return m.MsgFlag == MsgId; }) == null)
                {
                    _queue.Add(new BaseMsg
                    {
                        CreateTime = DateTime.Now,
                        FromUser = FromUserName,
                        MsgFlag = MsgId
                    });
                }                else
                {                    return null;
                }
               
            }            else
            {                if (_queue.FirstOrDefault(m => { return m.MsgFlag == CreateTime; }) == null)
                {
                    _queue.Add(new BaseMsg
                    {
                        CreateTime = DateTime.Now,
                        FromUser = FromUserName,
                        MsgFlag = CreateTime
                    });
                }                else
                {                    return null;
                }
            }

當(dāng)訊息已經(jīng)存在佇列中時,則不轉(zhuǎn)換目前的訊息為實體了,直接傳回null,呼叫的時候,當(dāng)傳回null時就不做任何處理。

下面開始講解事件訊息。接上篇講。所有的訊息都繼承BaseMessage,而所有的事件類型都包含一個Event的屬性。這裡為了方便調(diào)用,將訊息類型定義為枚舉,程式碼如下:

/// <summary>
    /// 事件類型枚舉    /// </summary>
    public enum Event
    {        /// <summary>
        /// 非事件類型        /// </summary>        NOEVENT,        /// <summary>
        /// 訂閱        /// </summary>        SUBSCRIBE,        /// <summary>
        /// 取消訂閱        /// </summary>        UNSUBSCRIBE,        /// <summary>
        /// 掃描帶參數(shù)的二維碼        /// </summary>        SCAN,        /// <summary>
        /// 地理位置        /// </summary>        LOCATION,        /// <summary>
        /// 單擊按鈕        /// </summary>        CLICK,        /// <summary>
        /// 鏈接按鈕        /// </summary>        VIEW,        /// <summary>
        /// 掃碼推事件        /// </summary>        SCANCODE_PUSH,        /// <summary>
        /// 掃碼推事件且彈出“消息接收中”提示框        /// </summary>        SCANCODE_WAITMSG,        /// <summary>
        /// 彈出系統(tǒng)拍照發(fā)圖        /// </summary>        PIC_SYSPHOTO,        /// <summary>
        /// 彈出拍照或者相冊發(fā)圖        /// </summary>        PIC_PHOTO_OR_ALBUM,        /// <summary>
        /// 彈出微信相冊發(fā)圖器        /// </summary>        PIC_WEIXIN,        /// <summary>
        /// 彈出地理位置選擇器        /// </summary>        LOCATION_SELECT,        /// <summary>
        /// 模板消息推送        /// </summary>        TEMPLATESENDJOBFINISH
    }

定義好枚舉後,就是定義訊息實體了。

追蹤/取消追蹤事件

xml封包如下:

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[FromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[subscribe]]></Event></xml>

對應(yīng)的實體:

/// <summary>
    /// 訂閱/取消訂閱事件    /// </summary>
    public class SubEventMessage : EventMessage
    {        private string _eventkey;        /// <summary>
        /// 事件KEY值,qrscene_為前綴,后面為二維碼的參數(shù)值(已去掉前綴,可以直接使用)        /// </summary>
        public string EventKey
        {            get { return _eventkey; }            set { _eventkey = value.Replace("qrscene_", ""); }
        }        /// <summary>
        /// 二維碼的ticket,可用來換取二維碼圖片        /// </summary>
        public string Ticket { get; set; }

    }

這裡要注意的是,當(dāng)使用者掃描帶有參數(shù)的二維碼時,如果使用者沒有關(guān)注目前公眾號,使用者追蹤時,會在訊息體中帶上qrscene_參數(shù),和Ticket,所以這裡定義了兩個屬性:EventKey,Ticket 。當(dāng)EventKey被賦值時,替換掉qrscene_,因為我們真正需要的就是後面的參數(shù)。

掃描帶參數(shù)二維碼事件

使用者掃描帶場景值二維碼時,可能推送兩種事件:

  1. #如果使用者尚未追蹤公眾號,則使用者可以追蹤公眾號,追蹤後微信會將帶場景值關(guān)注事件推送給開發(fā)者。

  2. 如果使用者已經(jīng)關(guān)注公眾號,則微信會將帶場景值掃描事件推送給開發(fā)者。 、

第一種上面已經(jīng)講了,這裡就只說明下第二種。

使用者已關(guān)注時的事件推送

xml套件如下:

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[FromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[SCAN]]></Event><EventKey><![CDATA[SCENE_VALUE]]></EventKey><Ticket><![CDATA[TICKET]]></Ticket></xml>

對應(yīng)的實體如下:

/// <summary>
    /// 掃描帶參數(shù)的二維碼實體    /// </summary>
    public class ScanEventMessage : EventMessage
    {        /// <summary>
        /// 事件KEY值,是一個32位無符號整數(shù),即創(chuàng)建二維碼時的二維碼scene_id        /// </summary>
        public string EventKey { get; set; }        /// <summary>
        /// 二維碼的ticket,可用來換取二維碼圖片        /// </summary>
        public string Ticket { get; set; }

    }

上報地理位置事件

當(dāng)公眾號開啟上報地理位置功能後,每次進(jìn)入公眾號會話時,用戶同意上報地理位置後,都會在進(jìn)入時上報地理位置,或在進(jìn)入回話後每5秒上報一次地理位置,公眾號可以再公眾平臺的後臺中修改設(shè)定。回報地理位置時,微信會將上報地理位置事件推播到開發(fā)者填寫的url。

xml封包如下:

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[LOCATION]]></Event><Latitude>23.137466</Latitude><Longitude>113.352425</Longitude><Precision>119.385040</Precision></xml>

對應(yīng)的實體如下:

/// <summary>
    /// 上報地理位置實體    /// </summary>
    public class LocationEventMessage : EventMessage
    {        /// <summary>
        /// 地理位置緯度        /// </summary>
        public string Latitude { get; set; }        /// <summary>
        /// 地理位置經(jīng)度        /// </summary>
        public string Longitude { get; set; }       /// <summary>
        /// 地理位置精度       /// </summary>
        public string Precision { get; set; }

    }

自定義菜單事件常用的事件有:click,view,scancode_puth,scancode_waitmsg,location_select。另外還有三種發(fā)圖的事件,由于并不常用,筆者也沒想到使用場景,再次就不一一講述了,有興趣的可以自己研究下,或者和我進(jìn)行交流。

click事件推送的xml數(shù)據(jù)包:

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[FromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[CLICK]]></Event><EventKey><![CDATA[EVENTKEY]]></EventKey></xml>

view事件推送的xml數(shù)據(jù)包和click的格式是一樣的,所以定義一個類就可以了,如下:

/// <summary>
    /// 普通菜單事件,包括click和view    /// </summary>
    public class NormalMenuEventMessage : EventMessage
    {        /// <summary>
        /// 事件KEY值,設(shè)置的跳轉(zhuǎn)URL        /// </summary>
        public string EventKey { get; set; }
  

    }

scancode事件的xml數(shù)據(jù)包如下:

<xml><ToUserName><![CDATA[ToUserName]]></ToUserName><FromUserName><![CDATA[FromUserName]]></FromUserName><CreateTime>1419265698</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[scancode_push]]></Event><EventKey><![CDATA[EventKey]]></EventKey><ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType><ScanResult><![CDATA[http://weixin.qq.com/r/JEy5oRLE0U_urVbC9xk2]]></ScanResult></ScanCodeInfo></xml>

對應(yīng)的實體如下:

/// <summary>
    /// 菜單掃描事件    /// </summary>
    public class ScanMenuEventMessage : EventMessage
    {        /// <summary>
        /// 事件KEY值        /// </summary>
        public string EventKey { get; set; }        /// <summary>
        /// 掃碼類型。qrcode是二維碼,其他的是條碼        /// </summary>
        public string ScanType { get; set; }        /// <summary>
        /// 掃描結(jié)果        /// </summary>
        public string ScanResult { get; set; }
    }

至此,當(dāng)前常用的事件類型消息都已定義完畢,結(jié)合上一篇所講的,將xml數(shù)據(jù)包轉(zhuǎn)換成對象的完整代碼如下:

public class MessageFactory
    {        private static List _queue; 
        public static BaseMessage CreateMessage(string xml)
        {            if (_queue == null)
            {
                _queue = new List<BaseMsg>();
            }            else if(_queue.Count>=50)
            {
                _queue = _queue.Where(q => { return q.CreateTime.AddSeconds(20) > DateTime.Now; }).ToList();//保留20秒內(nèi)未響應(yīng)的消息            }
            XElement xdoc = XElement.Parse(xml);            var msgtype = xdoc.Element("MsgType").Value.ToUpper();            var FromUserName = xdoc.Element("FromUserName").Value;            var MsgId = xdoc.Element("MsgId").Value;            var CreateTime = xdoc.Element("CreateTime").Value;
            MsgType type = (MsgType)Enum.Parse(typeof(MsgType), msgtype);            if (type!=MsgType.EVENT)
            {                if (_queue.FirstOrDefault(m => { return m.MsgFlag == MsgId; }) == null)
                {
                    _queue.Add(new BaseMsg
                    {
                        CreateTime = DateTime.Now,
                        FromUser = FromUserName,
                        MsgFlag = MsgId
                    });
                }                else
                {                    return null;
                }
               
            }            else
            {                if (_queue.FirstOrDefault(m => { return m.MsgFlag == CreateTime; }) == null)
                {
                    _queue.Add(new BaseMsg
                    {
                        CreateTime = DateTime.Now,
                        FromUser = FromUserName,
                        MsgFlag = CreateTime
                    });
                }                else
                {                    return null;
                }
            }            switch (type)
            {                case MsgType.TEXT: return Utils.ConvertObj(xml);                case MsgType.IMAGE: return Utils.ConvertObj(xml);                case MsgType.VIDEO: return Utils.ConvertObj(xml);                case MsgType.VOICE: return Utils.ConvertObj(xml);                case MsgType.LINK:                    return Utils.ConvertObj(xml);                case MsgType.LOCATION:                    return Utils.ConvertObj(xml);                case MsgType.EVENT://事件類型                {                    var eventtype = (Event)Enum.Parse(typeof(Event), xdoc.Element("Event").Value.ToUpper());                    switch (eventtype)
                    {                        case Event.CLICK:                            return Utils.ConvertObj(xml);                        case Event.VIEW: return Utils.ConvertObj(xml);                        case Event.LOCATION: return Utils.ConvertObj(xml);                        case Event.LOCATION_SELECT: return Utils.ConvertObj(xml);                        case Event.SCAN: return Utils.ConvertObj(xml);                        case Event.SUBSCRIBE: return Utils.ConvertObj(xml);                        case Event.UNSUBSCRIBE: return Utils.ConvertObj(xml);                        case Event.SCANCODE_WAITMSG: return Utils.ConvertObj(xml);                        default:                            return Utils.ConvertObj(xml);
                    }
                } break;                default:                    return Utils.ConvertObj(xml);
            }
        }
    }

【相關(guān)推薦】

1.微信公眾號平臺源碼下載

2.微信啦啦外賣2.2.4解密開源版 微信魔方源碼

以上是微信開發(fā)之接收事件推播與訊息排重的詳細(xì)內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1600
29
PHP教程
1502
276
PHP微信開發(fā):如何實作訊息加密解密 PHP微信開發(fā):如何實作訊息加密解密 May 13, 2023 am 11:40 AM

PHP是一種開源的腳本語言,廣泛應(yīng)用於網(wǎng)頁開發(fā)和伺服器端編程,尤其在微信開發(fā)中得到了廣泛的應(yīng)用。如今,越來越多的企業(yè)和開發(fā)者開始使用PHP進(jìn)行微信開發(fā),因為它成為了真正的易學(xué)易用的開發(fā)語言。在微信開發(fā)中,訊息的加密和解密是一個非常重要的問題,因為它們涉及資料的安全性。對於沒有加密和解密方式的消息,駭客可以輕鬆取得其中的數(shù)據(jù),對用戶造成威脅

PHP微信開發(fā):如何實現(xiàn)投票功能 PHP微信開發(fā):如何實現(xiàn)投票功能 May 14, 2023 am 11:21 AM

在微信公眾號開發(fā)中,投票功能經(jīng)常被運(yùn)用。投票功能是讓使用者快速參與互動的好方式,也是舉辦活動和調(diào)查意見的重要工具。本文將為您介紹如何使用PHP實作微信投票功能。在取得微信公眾號授權(quán)首先,你需要取得微信公眾號的授權(quán)。在微信公眾平臺上,你需要設(shè)定微信公眾號碼的api地址、官方帳號和公眾號碼對應(yīng)的token。在我們使用PHP語言開發(fā)的過程中,我們需要使用微信官方提供的PH

用PHP開發(fā)微信群發(fā)工具 用PHP開發(fā)微信群發(fā)工具 May 13, 2023 pm 05:00 PM

隨著微信的普及,越來越多的企業(yè)開始將其作為行銷工具。而微信群發(fā)功能,則是企業(yè)進(jìn)行微信行銷的重要手段之一。但是,如果只依靠手動發(fā)送,對於行銷人員來說是一件極為費(fèi)時費(fèi)力的工作。所以,開發(fā)一款微信群發(fā)工具就顯得格外重要。本文將介紹如何使用PHP開發(fā)微信群發(fā)工具。一、準(zhǔn)備工作開發(fā)微信群發(fā)工具,我們需要掌握以下幾個技術(shù)點:PHP基礎(chǔ)知識微信公眾平臺開發(fā)開發(fā)工具:Sub

PHP微信開發(fā):如何實現(xiàn)客服聊天視窗管理 PHP微信開發(fā):如何實現(xiàn)客服聊天視窗管理 May 13, 2023 pm 05:51 PM

微信是目前全球用戶規(guī)模最大的社群平臺之一,隨著行動網(wǎng)路的普及,越來越多的企業(yè)開始意識到微信行銷的重要性。在進(jìn)行微信行銷時,客服服務(wù)是至關(guān)重要的一環(huán)。為了更好地管理客服聊天窗口,我們可以藉助PHP語言進(jìn)行微信開發(fā)。一、PHP微信開發(fā)簡介PHP是一種開源的伺服器端腳本語言,廣泛用於Web開發(fā)領(lǐng)域。結(jié)合微信公眾平臺提供的開發(fā)接口,我們可以使用PHP語言進(jìn)行微信

PHP微信開發(fā):如何實現(xiàn)使用者標(biāo)籤管理 PHP微信開發(fā):如何實現(xiàn)使用者標(biāo)籤管理 May 13, 2023 pm 04:31 PM

在微信公眾號開發(fā)中,使用者標(biāo)籤管理是一個非常重要的功能,可以讓開發(fā)者更了解和管理自己的使用者。本篇文章將介紹如何使用PHP實作微信使用者標(biāo)籤管理功能。一、取得微信用戶openid在使用微信用戶標(biāo)籤管理功能之前,我們首先需要取得用戶的openid。在微信公眾號開發(fā)中,透過使用者授權(quán)的方式取得openid是比較常見的做法。在使用者授權(quán)完成後,我們可以透過以下程式碼取得用

PHP微信開發(fā):如何實作群發(fā)訊息傳送記錄 PHP微信開發(fā):如何實作群發(fā)訊息傳送記錄 May 13, 2023 pm 04:31 PM

隨著微信成為了人們生活中越來越重要的通訊工具,其敏捷的訊息傳遞功能迅速受到廣大企業(yè)和個人的青睞。對企業(yè)而言,將微信發(fā)展為一個行銷平臺已經(jīng)成為趨勢,而微信開發(fā)的重要性也逐漸凸顯。在其中,群發(fā)功能更是被廣泛使用,那麼,作為PHP程式設(shè)計師,如何實現(xiàn)群發(fā)訊息發(fā)送記錄呢?以下將為大家簡單介紹一下。 1.了解微信公眾號相關(guān)開發(fā)知識在了解如何實現(xiàn)群發(fā)訊息發(fā)送記錄之前,我

使用PHP實現(xiàn)微信公眾號開發(fā)的步驟 使用PHP實現(xiàn)微信公眾號開發(fā)的步驟 Jun 27, 2023 pm 12:26 PM

如何使用PHP實現(xiàn)微信公眾號開發(fā)微信公眾號已經(jīng)成為了許多企業(yè)推廣和互動的重要管道,而PHP作為常用的Web語言,也可以用來進(jìn)行微信公眾號的開發(fā)。本文將介紹使用PHP實現(xiàn)微信公眾號開發(fā)的具體步驟。第一步:取得微信公眾號的開發(fā)者帳號在開始微信公眾號開發(fā)之前,需要先去申請一個微信公眾號的開發(fā)者帳號。具體的註冊流程可參考微信公眾平臺的官方網(wǎng)

如何使用PHP進(jìn)行微信開發(fā)? 如何使用PHP進(jìn)行微信開發(fā)? May 21, 2023 am 08:37 AM

隨著網(wǎng)路和行動智慧型裝置的發(fā)展,微信成為了社交和行銷領(lǐng)域不可或缺的一部分。在這個越來越數(shù)位化的時代,如何使用PHP進(jìn)行微信開發(fā)已經(jīng)成為了許多開發(fā)者的關(guān)注點。本文主要介紹如何使用PHP進(jìn)行微信發(fā)展的相關(guān)知識點,以及其中的一些技巧和注意事項。一、開發(fā)環(huán)境準(zhǔn)備在進(jìn)行微信開發(fā)之前,首先需要準(zhǔn)備好對應(yīng)的開發(fā)環(huán)境。具體來說,需要安裝PHP的運(yùn)作環(huán)境,以及微信公眾平臺提

See all articles