Heim  >  Artikel  >  WeChat-Applet  >  WeChat-Entwicklung für den Empfang von Event-Push und die Deduplizierung von Nachrichten

WeChat-Entwicklung für den Empfang von Event-Push und die Deduplizierung von Nachrichten

Y2J
Y2JOriginal
2017-05-09 09:39:122277Durchsuche

Wie im vorherigen Blogbeitrag erwähnt, können WeChat-Nachrichten grob in zwei Typen unterteilt werden: Zum einen handelt es sich um gewöhnliche Nachrichten, einschließlich Text, Sprache, Bilder usw., und zum anderen um den Ereignistyp, der in diesem Artikel besprochen wird. . Einschließlich: Verfolgen/Entfolgen von Ereignissen, Scannen von QR-Code-Ereignissen mit Parametern, Melden von geografischen Standortereignissen, benutzerdefinierte menübezogene Ereignisse usw. In diesem Artikel werden sie einzeln erläutert.

Wie im vorherigen Artikel erwähnt: Wenn der WeChat-Server innerhalb von 5 Sekunden keine Antwort erhält, wird die Verbindung getrennt und die Anfrage erneut gestartet, wobei es insgesamt dreimal erneut versucht wird. In diesem Fall tritt ein Problem auf. Es gibt ein solches Szenario: Wenn ein Benutzer einem WeChat-Konto folgt, werden die aktuellen Benutzerinformationen abgerufen und diese Informationen dann in die Datenbank geschrieben. Ähnlich wie bei der Registrierung auf der PC-Website. Vielleicht ist die Geschäftslogik, mit der wir umgehen müssen, aufgrund dieser Bedenken relativ komplex. Zum Beispiel das Senden von Punkten, das Schreiben von Benutzerprotokollen und das Zuweisen von Benutzergruppen. Warten Sie ... Eine Reihe von Logik muss ausgeführt werden, oder die Netzwerkumgebung ist relativ komplex und es gibt keine Garantie dafür, dass der Vorgang des aktuellen Benutzers innerhalb von 5 Sekunden beantwortet wird. Wenn der Vorgang noch nicht abgeschlossen ist, wird der WeChat-Server verwendet schiebt das gleiche Aufmerksamkeitsereignis auf unseren Server. Wir werden unsere Logik erneut ausführen, was zu doppelten Daten in der Datenbank führen kann (einige Kinderschuhe werden sagen, ich stelle zuerst fest, ob sie bereits vorhanden sind, bevor Daten eingefügt werden ). Es existiert, was ich sagen möchte, ist, dass ich das am Anfang dachte, aber es gibt immer noch eine Lücke zwischen der realen Betriebsumgebung und unserer Debugging-Umgebung, bis ich feststellte, dass es viele Duplikate gab Benutzerinformationen in der Datenbank, I Erst dann wurde mir klar, wie wichtig die Nachrichtendeduplizierung ist.

Bei der Nachrichtendeduplizierung gibt es einen Unterschied zwischen normalen Nachrichten und Ereignisnachrichten. Gewöhnliche Nachrichten verwenden msgid, während Ereignisnachrichten FromUserName + CreateTime verwenden. Meine Idee ist:

  1. Erstellen Sie eine neue Klasse BaseMsg mit drei Attributen , nämlich FromUser, MsgFlag und CreateTime. Der Code lautet wie folgt:

  2. public class BaseMsg
        {        /// <summary>
            /// 发送者标识        /// </summary>
            public string FromUser { get; set; }        /// <summary>
            /// 消息表示。普通消息时,为msgid,事件消息时,为事件的创建时间        /// </summary>
            public string MsgFlag { get; set; }        /// <summary>
            /// 添加到队列的时间        /// </summary>
            public DateTime CreateTime { get; set; }
        }
  3. Erstellen Sie eine statischelist_queue zum Speichern der Nachrichtenliste. Der Typ der Liste ist List< ;BaseMsg> ;.

  4. Stellen Sie vor der Verarbeitung des WeChat-Nachrichtentexts zunächst fest, ob die Liste instanziiert ist. Andernfalls stellen Sie fest, ob die Länge der Liste größer als oder ist gleich 50 (dies kann automatisch erfolgen). Der Zweck ist die Anzahl gleichzeitiger Nachrichten auf WeChat. Wenn er größer oder gleich 50 ist, werden Nachrichten, die nicht innerhalb von 20 Sekunden geantwortet haben, beibehalten (alle 5 Sekunden erneut versuchen). , insgesamt 3 Wiederholungsversuche, also 15 Sekunden. Zur Sicherheit schreiben Sie hier 20 Sekunden.

  5. Ermitteln Sie den Nachrichtentyp des aktuellen Nachrichtentexts und bestimmen Sie anhand von _queue, ob die aktuelle Nachricht angefordert wurde. Wenn es sich um ein Ereignis handelt, werden FromUser und Erstellungszeit gespeichert. Wenn es sich um eine normale Nachricht handelt, wird MsgFlag gespeichert. Das Folgende ist der Code:

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秒内未响应的消息            }
            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;
                }
            }

Wenn die Nachricht bereits in der Warteschlange vorhanden ist, wird die aktuelle Nachricht nicht in eine Entität umgewandelt und beim Aufruf direkt null zurückgegeben null wird zurückgegeben, es findet keine Verarbeitung statt.

Im Folgenden werden die Neuigkeiten zur Veranstaltung erläutert. Fortsetzung des vorherigen Artikels. Alle Nachrichten erben BaseMessage und alle Ereignistypen enthalten eine Event-Eigenschaft. Zur Vereinfachung des Aufrufs wird der Nachrichtentyp als Aufzählung definiert. Der Code lautet wie folgt:

/// <summary>
    /// 事件类型枚举    /// </summary>
    public enum Event
    {        /// <summary>
        /// 非事件类型        /// </summary>        NOEVENT,        /// <summary>
        /// 订阅        /// </summary>        SUBSCRIBE,        /// <summary>
        /// 取消订阅        /// </summary>        UNSUBSCRIBE,        /// <summary>
        /// 扫描带参数的二维码        /// </summary>        SCAN,        /// <summary>
        /// 地理位置        /// </summary>        LOCATION,        /// <summary>
        /// 单击按钮        /// </summary>        CLICK,        /// <summary>
        /// 链接按钮        /// </summary>        VIEW,        /// <summary>
        /// 扫码推事件        /// </summary>        SCANCODE_PUSH,        /// <summary>
        /// 扫码推事件且弹出“消息接收中”提示框        /// </summary>        SCANCODE_WAITMSG,        /// <summary>
        /// 弹出系统拍照发图        /// </summary>        PIC_SYSPHOTO,        /// <summary>
        /// 弹出拍照或者相册发图        /// </summary>        PIC_PHOTO_OR_ALBUM,        /// <summary>
        /// 弹出微信相册发图器        /// </summary>        PIC_WEIXIN,        /// <summary>
        /// 弹出地理位置选择器        /// </summary>        LOCATION_SELECT,        /// <summary>
        /// 模板消息推送        /// </summary>        TEMPLATESENDJOBFINISH
    }

Nach der Definition der Aufzählung ist es an der Zeit, die Nachrichtenentität zu definieren.

Ereignis verfolgen/entfolgen

Das XML-Datenpaket lautet wie folgt:

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

Entsprechende Entität:

/// <summary>
    /// 订阅/取消订阅事件    /// </summary>
    public class SubEventMessage : EventMessage
    {        private string _eventkey;        /// <summary>
        /// 事件KEY值,qrscene_为前缀,后面为二维码的参数值(已去掉前缀,可以直接使用)        /// </summary>
        public string EventKey
        {            get { return _eventkey; }            set { _eventkey = value.Replace("qrscene_", ""); }
        }        /// <summary>
        /// 二维码的ticket,可用来换取二维码图片        /// </summary>
        public string Ticket { get; set; }

    }

Hier ist zu beachten, dass beim Scannen des QR-Codes mit Parametern durch den Benutzer, wenn der Benutzer nicht dem aktuellen offiziellen Konto folgt, die Parameter qrscene_ und Ticket in den Nachrichtentext aufgenommen werden, also zwei Attribute werden hier definiert:EventKey,Ticket. Wenn Sie EventKey einen Wert zuweisen, ersetzen Sie qrscene_, denn was wir wirklich brauchen, sind die folgenden Parameter.

QR-Code-Ereignis mit Parametern scannen

Wenn der Benutzer den QR-Code mit Szenenwert scannt, können zwei Ereignisse übertragen werden:

  1. Wenn der Benutzer dem offiziellen Konto nicht gefolgt ist, kann er dem offiziellen Konto folgen. Nachdem er dem offiziellen Konto gefolgt ist, sendet WeChat das Follow-Ereignis mit dem Szenenwert an den Entwickler.

  2. Wenn der Benutzer dem offiziellen Konto gefolgt ist, leitet WeChat das Ereignis zum Scannen des Szenenwerts an den Entwickler weiter. ,

Der erste Typ wurde oben besprochen, und nur der zweite Typ wird hier erklärt.

Ereignis-Push, wenn der Benutzer gefolgt ist

Das XML-Paket lautet wie folgt:

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

Die entsprechenden Entitäten sind wie folgt:

/// <summary>
    /// 扫描带参数的二维码实体    /// </summary>
    public class ScanEventMessage : EventMessage
    {        /// <summary>
        /// 事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id        /// </summary>
        public string EventKey { get; set; }        /// <summary>
        /// 二维码的ticket,可用来换取二维码图片        /// </summary>
        public string Ticket { get; set; }

    }

Geografische Standortereignisse melden

Wenn das offizielle Konto die Funktion zur geografischen Standortberichterstattung aktiviert, jedes Mal, wenn der Benutzer die offizielle Kontositzung betritt und stimmt zu, den geografischen Standort zu melden, den geografischen Standort beim Betreten zu melden oder den geografischen Standort alle 5 Sekunden nach Betreten des Gesprächs zu melden. Das offizielle Konto kann die Einstellungen im Hintergrund der offiziellen Plattform ändern. Beim Melden des geografischen Standorts sendet WeChat das gemeldete geografische Standortereignis an die vom Entwickler eingegebene URL.

Das XML-Datenpaket lautet wie folgt:

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

Die entsprechende Entität lautet wie folgt:

/// <summary>
    /// 上报地理位置实体    /// </summary>
    public class LocationEventMessage : EventMessage
    {        /// <summary>
        /// 地理位置纬度        /// </summary>
        public string Latitude { get; set; }        /// <summary>
        /// 地理位置经度        /// </summary>
        public string Longitude { get; set; }       /// <summary>
        /// 地理位置精度       /// </summary>
        public string Precision { get; set; }

    }

自定义菜单事件常用的事件有:click,view,scancode_puth,scancode_waitmsg,location_select。另外还有三种发图的事件,由于并不常用,笔者也没想到使用场景,再次就不一一讲述了,有兴趣的可以自己研究下,或者和我进行交流。

click事件推送的xml数据包:

<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数据包和click的格式是一样的,所以定义一个类就可以了,如下:

/// <summary>
    /// 普通菜单事件,包括click和view    /// </summary>
    public class NormalMenuEventMessage : EventMessage
    {        /// <summary>
        /// 事件KEY值,设置的跳转URL        /// </summary>
        public string EventKey { get; set; }
  

    }

scancode事件的xml数据包如下:

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

对应的实体如下:

/// <summary>
    /// 菜单扫描事件    /// </summary>
    public class ScanMenuEventMessage : EventMessage
    {        /// <summary>
        /// 事件KEY值        /// </summary>
        public string EventKey { get; set; }        /// <summary>
        /// 扫码类型。qrcode是二维码,其他的是条码        /// </summary>
        public string ScanType { get; set; }        /// <summary>
        /// 扫描结果        /// </summary>
        public string ScanResult { get; set; }
    }

至此,当前常用的事件类型消息都已定义完毕,结合上一篇所讲的,将xml数据包转换成对象的完整代码如下:

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秒内未响应的消息            }
            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);
            }
        }
    }

【相关推荐】

1.微信公众号平台源码下载

2.微信啦啦外卖2.2.4解密开源版 微信魔方源码

Das obige ist der detaillierte Inhalt vonWeChat-Entwicklung für den Empfang von Event-Push und die Deduplizierung von Nachrichten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn