本文作者:小黑黑

[微信]消息去重、消息加密、记录日志

小黑黑 1年前 ( 2019-03-27 ) 529 抢沙发
[微信]消息去重、消息加密、记录日志摘要: 一、消息去重       消息去重在微信开发中非常重要,要了解消息去重的原理,我们就要先了解微信消息的容错机制,当微信客户端发送一条消息时,...

一、消息去重

       消息去重在微信开发中非常重要,要了解消息去重的原理,我们就要先了解微信消息的容错机制,当微信客户端发送一条消息时,首先会发送到微信服务器,再由微信服务器发送到我们的应用服务器,如果是因为我们的应用服务器内部出现错误,或执行一个业务逻辑耗时较长,那么微信服务器在五秒内收不到我们应用服务器的响应会断掉连接,并且重新发起请求,总共重试三次。如果超过5秒后微信用户接收不到消息,相信用户应该会感到非常的诧异。

       如果是普通的静态消息,对于我们来说产生的后果还不是严重的,但如果是需要修改数据库信息,比如:修改用户余额,当用户第一次发送消息没有接收到响应信息,那么有可能就会重复的发送请求,这就造成了数据库用户余额的多次修改,这对我们来说是不能接受的。

       那么我们怎样实现消息去重呢?在前面我们讲过微信消息的通信过程,里面就有一个请求的XML格式,里面包含了一个MsgId,当我们的应用服务器超过5秒没有对微信服务器进行回应,那么微信服务器将会重新发送请求,并且MsgId一致,共重试3次,那么我们就可以使用MsgId来进行去重。我们只需要在实例化MessageHandler之后,将OmitRepeatedMessage属性设置为true即可。默认情况下OmitRepeatedMessage为true。

//创建MessageHandler实例,对微信请求的详细判断都在这里面
var messageHandler = new CustomMessageHandler(Request.GetRequestMemoryStream(), postModel, 10);
messageHandler.OmitRepeatedMessage = true;

除了直接设置OmitRepeatedMessage属性外,我们还可以在执行OnExecuting()之前对去重的条件进行动态地判断,我们可以在自定义的CustomMessageHandler中设置OmitRepeatedMessageFunc委托方法即可。

public CustomMessageHandler(Stream inputStream, PostModel postModel, int maxRecordCount = 0)
    : base(inputStream, postModel, maxRecordCount)
{
    base.OmitRepeatedMessageFunc = requestMessage =>
    {

        if (RequestMessage is RequestMessageText)
        {
            var textMessage = RequestMessage as RequestMessageText;
            if (textMessage.Content == "不去重")
            {
                return false;
            }
        }

        return true;
    };
}

具体是怎么实现的呢,当我们将OmitRepeatedMessage属性设置为true时,在执行OnExecuting()时,会判断此属性,如果是重复消息,那么将会把CancelExcute属性设置为true。

public virtual void OnExecuting()()
{
    //消息去重
    if ((OmitRepeatedMessageFunc == null || OmitRepeatedMessageFunc(RequestMessage) == true) 
        && OmitRepeatedMessage && CurrentMessageContext.RequestMessages.Count > 1
        //&& !(RequestMessage is RequestMessageEvent_Merchant_Order)批量订单的MsgId可能会相同
        )
    {
        var lastMessage = CurrentMessageContext.RequestMessages[CurrentMessageContext.RequestMessages.Count - 2];
        if ((lastMessage.MsgId != 0 && lastMessage.MsgId == RequestMessage.MsgId)//使用MsgId去重
            ||
            ((lastMessage.CreateTime == RequestMessage.CreateTime && lastMessage.MsgType == RequestMessage.MsgType))//使用CreateTime去重(OpenId对象已经是同一个)
            )
        {
            CancelExcute = true;//重复消息,取消执行
            return;
        }
    }
    base.OnExecuting()();
}

二、消息加密

      处于对安全的考虑,微信提供了消息加密的方法,并推荐我们使用。微信公众号后台要求开发者填写EncodingAESKey,或者是自动生成。

      在前面我们介绍Init()方法时,有提到SDK会根据消息是否加密进行解密操作,最后返回微信服务器消息时也会根据是否加密来进行加密工作,MessageHandler已经对消息的加密和解密进行了全自动工作,我们开发者不用关心具体的加密和解密过程。要想使用加密,我们只需要在实例化MessageHandler之前为PostModel的EncodingAESKey属性进行赋值即可。

postModel.EncodingAESKey = "EncodingAESKey";

//创建MessageHandler实例,对微信请求的详细判断都在这里面
var messageHandler = new CustomMessageHandler(Request.GetRequestMemoryStream(), postModel, 10);

三、记录日志

       为了方便我们开发者在开发环境中能够更加清晰的看到请求消息和返回消息的内容,以便我们能够处理一些问题,sdk还未我们提供了记录请求日志和记录响应日志的功能,使用该功能十分简单,我们只需要在执行messageHandler.Execute();的前后添加请求日志和响应日志即可。

//记录请求日志
messageHandler.SaveRequestMessageLog();

//执行微信消息处理过程
messageHandler.Execute();

//记录响应日志
messageHandler.SaveResponseMessageLog();

这样我们每次接收到的请求信息和响应信息将会保存到App_Data文件夹下,当然我们也可以指定文件路径,这样就可以帮助我们排查一些问题了。

分享到: 网站分享代码

发表评论

快捷回复:

评论列表 (暂无评论,529人围观)参与讨论

还没有评论,来说两句吧...