• 微信公众平台开发教程(三) 基础框架搭建


    上一章,我们已经初步讲解了微信公众账号开发的基本原理,今天我们来探索设计实现。

    首先我们设计了模块层次图,当然图中只是给出一种实现方式,不局限于此。具体见下图。

    主要功能介绍如下:

    1)请求接口层。处理HTTP请求,及响应

    2)分发层。由接口层传入请求,然后具体分析请求类型,分发至不同的处理器

    3)业务逻辑层。这里是我们的具体业务逻辑了,根据请求,实现具体的业务逻辑。

    4)数据层。我们在实现某个应用时可能需要访问数据,可以是数据库或者是文件。如果是简单应用,可能没有这一层。

    其实,具体的应用可以在这个结构上去扩展,可以扩展消息对象层、业务对象层、数据访问层、功能管理层等。这里只是提供一种思路,不局限于此。

     

    根据层次图,设计流程图,具体讲述实现的各个过程。以便了解整个处理过程。如下图所示:

      

    根据流程图,我们能够清晰的了解整个流程,消息处理的具体实现步骤。

    下面我们针对每个流程进行代码实现。

    一、接收HTTP请求

    我们需要一个HttpHandler或者一个网页,来处理微信服务端HTTP请求。

    这里我们使用了HttpHandler。因为其灵活性高,性能好。

    具体实现如下。

    复制代码
        public class WeiXinHttpHandler:IHttpHandler
        {
            /// <summary>
            /// 
            /// </summary>
            public bool IsReusable
            {
                get { return true; }
            }
            /// <summary>
            /// 处理请求
            /// </summary>
            /// <param name="context"></param>
            public void ProcessRequest(HttpContext context)
            {
                //由微信服务接收请求,具体处理请求
                WeiXinService wxService = new WeiXinService(context.Request);
                string responseMsg = wxService.Response();
                context.Response.Clear();
                context.Response.Charset = "UTF-8";
                context.Response.Write(responseMsg);
                context.Response.End();
            }
        }
    复制代码

    如果是HTTPHandler,需要在配置文件中,配置具体的应用。具体的节点配置,我们不作说明。直接给出例子,配置HttpHandler节点如下

    <httpHandlers>
       <add verb="*" path="WXService.ashx" type="namespace.WeiXinHttpHandler,WXWeb" validate="true"/>
    </httpHandlers>

    二、分发请求

     为了能功能封装,我们也将此封装在了处理组件中。其实可以放置在HttpHandler中的。 

     1)验证签名

     如果是首次请求,需要验证签名。就相当于一次HTTP握手。之前在上一章中,设置的服务器URL以及token值,这个功能就是检验是否链接成功。

    这个请求是GET请求。以下具体说明(官方):

    业务逻辑:

    加密/校验流程:

    <1> 将token、timestamp、nonce三个参数进行字典序排序

    <2> 将三个参数字符串拼接成一个字符串进行SHA1加密

     <3> 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 

    而官方只提供了PHP的代码示例,很多东西在C#中并非直译既得。所以这里面也有一些具体处理。先看官方的代码: 

    复制代码
        private function checkSignature()
        {
            $signature = $_GET["signature"];
            $timestamp = $_GET["timestamp"];
            $nonce = $_GET["nonce"];    
                    
            $token = TOKEN;
            $tmpArr = array($token, $timestamp, $nonce);
            sort($tmpArr);
            $tmpStr = implode( $tmpArr );
            $tmpStr = sha1( $tmpStr );
            
            if( $tmpStr == $signature ){
                return true;
            }else{
                return false;
            }
        }
    复制代码

    我们将其翻译成C#版本: 

    复制代码
            /// <summary>
            /// 检查签名
            /// </summary>
            /// <param name="request"></param>
            /// <returns></returns>
            private bool CheckSignature()
            {
                string signature = Request.QueryString[SIGNATURE];
                string timestamp = Request.QueryString[TIMESTAMP];
                string nonce = Request.QueryString[NONCE];
    
                List<string> list = new List<string>();
                list.Add(TOKEN);
                list.Add(timestamp);
                list.Add(nonce);
                //排序
                list.Sort();
                //拼串
                string input = string.Empty;
                foreach (var item in list)
                {
                    input += item;
                }
                //加密
                string new_signature = SecurityUtility.SHA1Encrypt(input);
                //验证
                if (new_signature == signature)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
    复制代码

    这里需要SHA1加密,具体的算法如下:

    复制代码
            /// <summary>
            /// SHA1加密
            /// </summary>
            /// <param name="intput">输入字符串</param>
            /// <returns>加密后的字符串</returns>
            public static string SHA1Encrypt(string intput)
            {
                byte[] StrRes = Encoding.Default.GetBytes(intput);
                HashAlgorithm mySHA = new SHA1CryptoServiceProvider();
                StrRes = mySHA.ComputeHash(StrRes);
                StringBuilder EnText = new StringBuilder();
                foreach (byte Byte in StrRes)
                {
                    EnText.AppendFormat("{0:x2}", Byte);
                }
                return EnText.ToString();
            }
    复制代码

    2)分发请求

    接下来就是具体的消息请求了,这里都是POST请求。

    因为有多种消息类型,我们通过工厂类来进行封装,然后每种消息都有专门的处理器来进行处理。具体实现逻辑:

    复制代码
            /// <summary>
            /// 处理请求
            /// </summary>
            /// <returns></returns>
            private string ResponseMsg()
            {
                string requestXml = Common.ReadRequest(this.Request);
                IHandler handler = HandlerFactory.CreateHandler(requestXml);
                if (handler != null)
                {
                    return handler.HandleRequest();
                }
    
                return string.Empty;
            }
    复制代码

    处理请求的对外方法(HttpHandler调用的方法就是这个了),即:

    复制代码
            /// <summary>
            /// 处理请求,产生响应
            /// </summary>
            /// <returns></returns>
            public string Response()
            {
                string method = Request.HttpMethod.ToUpper();
                //验证签名
                if (method == "GET")
                {
                    if (CheckSignature())
                    {
                        return Request.QueryString[ECHOSTR];
                    }
                    else
                    {
                        return "error";
                    }
                }
    
                //处理消息
                if (method == "POST")
                {
                    return ResponseMsg();
                }
                else
                {
                    return "无法处理";
                }
            }
    复制代码

    三、消息处理器具体处理消息

    1)消息类型

    首先我们来看下,具体的消息类型,其实上一张中已经明确给了消息的接口。

    这里再看具体看一下,请求的消息类型有哪些,回复的消息类型有哪些等。

    千万要注意,请求的消息是文本类型,回复的消息,不一定也是文本哦,可以是图文、音乐等任意一种可回复的消息。具体见下表所示。

     

    2)根据具体的消息接口,设计消息类。

    这里给出类图,供参考。

    3)针对不同的消息,会有不同的处理器,来看下具体的类图。

      

    4)具体业务处理 

    每个handler里面就是可以处理具体请求。输入的什么消息,访问那些数据,调用服务等,都在这里处理。

    还是建议大家对具体的业务进行单独封装,在Handler中,只提供调用的接口。

    因为随着业务的增加,一个Handler可能要处理很多业务,如果所有的操作逻辑都写在这里,势必影响阅读,也不易于维护与扩展。 

    5)产生回复消息

    在处理完请求后,需要生成回复消息,响应到终端。消息格式,就是我们介绍那些消息类型,但必须是可用于回复的,当前支持的有:文本、图文、音乐等。

    一定要明确:回复的消息类型不一定要与请求的消息类型一样,比如,请求是文本,回复的可以是图文、音乐。

    产生回复消息的过程,其实,就是特定的消息对象格式化为对应的XML的过程,然后将XML响应至微信服务器。

    6)实例

    这里以微信用户关注公众账号,然后服务端处理处理事件请求,登记用户,并提示欢迎信息。

    复制代码
        class EventHandler : IHandler
        {
            /// <summary>
            /// 请求的xml
            /// </summary>
            private string RequestXml { get; set; }
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="requestXml"></param>
            public EventHandler(string requestXml)
            {
                this.RequestXml = requestXml;
            }
            /// <summary>
            /// 处理请求
            /// </summary>
            /// <returns></returns>
            public string HandleRequest()
            {
                string response = string.Empty;
                EventMessage em = EventMessage.LoadFromXml(RequestXml);
                if (em.Event == EventType.Subscribe)
                {
                    //注册用户
                    User user = new User();
                    user.OpenID = em.FromUserName;
                    UserManager.Regester(user);
    
                    //回复欢迎消息
                    TextMessage tm = new TextMessage();
                    tm.ToUserName = em.FromUserName;
                    tm.FromUserName = em.ToUserName;
                    tm.CreateTime = Common.GetNowTime();
                    tm.Content = "欢迎您关注xxx,我是小微。有什么我能帮助您的吗?";
                    response = tm.GenerateContent();
                }
    
                return response;
            }
        }
    复制代码

    四、HTTP响应

     最后将处理结果返回至最初HttpHandler,响应给微信服务器,直接Response处理。这也是在最开始设计的HttpHandler中实现的。

    下面是代码片段,具体可见一、Http请求 

                context.Response.Clear();
                context.Response.Charset = "UTF-8";
                context.Response.Write(responseMsg);
                context.Response.End();
  • 相关阅读:
    技术管理之路三、团队建设:怎么带队伍?
    技术管理之路五、管理沟通:管理的必修课!
    职场工作方法论:计划安排,时间管理的“四象限法则”
    职场工作方法论:目标管理SMART原则
    激励方法论1、马斯洛需求模型
    mybatis PageHelper 分页组件优化
    async 和 await
    spring cloud 负载均衡 平滑上下线
    vue 重新渲染组件
    spring cloud 超时整理
  • 原文地址:https://www.cnblogs.com/yyjie/p/7308823.html
Copyright © 2020-2023  润新知