本篇主要围绕的是自定义Web服务器的架构搭建.

  在上篇中"开发者中心"留下了两个词"URL"和"Token",URL指的是能够接收处理微信服务器发送的GET/POST请求的网址,该网址应该已部署到开发这的WEB服务器中,能被公网访问得到.Token是用作微信服务器与开发者Web服务器之间进行通信的安全签名,每次微信服务器和开发者Web服务器的通信都会含有该Token值经过加密后的信息,通过对比Token值,验证通信的安全性.Token用于防止未授权的第三方伪造身份,窃取信息.

 

 

实现URL接入:当微信服务器以get请求过来web服务器的时候,get请求会携带四个参数.

signature:微信加密签名,结合token,和请求中的timestamp,nonce参数.

timestamp:时间戳

nonce:随机数

echostr:随机字符串

开发者通过检验signature对请求进行校验,若来自微信服务器的get方式请求,原样返回echostr内容,则接入生效.成功连接上自定义服务器.

1.将token,timestamp,nonce三个参数进行字典排序

2.将三个参数字符串拼接成一个字符串进行sha1加密

3.获得加密后的字符串可与singnature对比,标识该请求来自微信服务器

/// <summary>
    /// Handler1 的摘要说明
    /// </summary>
    public class Handler1 : 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();
        }
    }

WeixinService:

public class WeiXinService
    {
        /// <summary>
        /// TOKEN
        /// </summary>
        private const string TOKEN = "YZR";
        /// <summary>
        /// 签名
        /// </summary>
        private const string SIGNATURE = "signature";
        /// <summary>
        /// 时间戳
        /// </summary>
        private const string TIMESTAMP = "timestamp";
        /// <summary>
        /// 随机数
        /// </summary>
        private const string NONCE = "nonce";
        /// <summary>
        /// 随机字符串
        /// </summary>
        private const string ECHOSTR = "echostr";     
        /// <summary>
        /// HttpRequest
        /// </summary>
        private HttpRequest Request { get; set; }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="request"></param>
        public WeiXinService(HttpRequest request)
        {
            this.Request = request;
        }
        /// <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 "无法处理";
            }
        }

        /// <summary>
        /// 处理请求
        /// </summary>
        /// <returns></returns>
        private string ResponseMsg()
        {
            string requestXml = Common.ReadRequest(this.Request);//得到Request的XML字符串信息
            IHandler handler = HandlerFactory.CreateHandler(requestXml);//处理器
            if (handler != null)
            {
                return handler.HandleRequest();//处理器处理请求
            }

            return string.Empty;
        }
        /// <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;
            }
        }
    }

    成功实现URL接入之后,订阅号发送Message过来将是以post的方式,信息是xml格式进行传递.格式节点为:
    /// 发送人
    public const string FROM_USERNAME = "FromUserName";
       
    /// 开发者微信号
    public const string TO_USERNAME = "ToUserName";
     
    // 消息内容
    public const string CONTENT = "Content";
       
    /// 消息创建时间 (整型)
    public const string CREATE_TIME = "CreateTime";
       
    /// 消息类型
    public const string MSG_TYPE = "MsgType"; //消息类型

   

        /// <summary>
        /// 读取请求对象的内容
        /// 只能读一次
        /// </summary>
        /// <param name="request">HttpRequest对象</param>
        /// <returns>XML字符串</returns>
        public static string ReadRequest(HttpRequest request) 
        {
            string reqStr = string.Empty;
            using (Stream s = request.InputStream)
            {
                using (StreamReader reader = new StreamReader(s, Encoding.UTF8))
                {
                    reqStr = reader.ReadToEnd();
                }
            }

            return reqStr;
        }

 

    在微信服务器转发过来的消息有MsgType,比如文本,声音,视频,事件等,我们这里先以文本消息作为演示:

   首先我们需要定义一个handler来处理这个文本处理类.

 

    /// <summary>
    /// 文本信息处理类
    /// </summary>
    public class TextHandler : IHandler
    {
        /// <summary>
        /// 请求的XML
        /// </summary>
        private string RequestXml { get; set; }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="requestXml">请求的xml</param>
        public TextHandler(string requestXml)
        {
            this.RequestXml = requestXml;
        }
        /// <summary>
        /// 处理请求
        /// </summary>
        /// <returns></returns>
        public string HandleRequest()
        {
            string response = string.Empty;
            TextMessage tm = TextMessage.LoadFromXml(RequestXml);
            string content = tm.Content.Trim();
            if (string.IsNullOrEmpty(content))
            {
                response = "请输入内容";
            }
            else
            {
               response = HandleOther(content);
            }
            tm.Content = response;
            //进行发送者、接收者转换
            string temp = tm.ToUserName;
            tm.ToUserName = tm.FromUserName;
            tm.FromUserName = temp;
            response = tm.GenerateContent();
            return response;
        }
        /// <summary>
        /// 处理其他消息
        /// </summary>
        /// <param name="tm"></param>
        /// <returns></returns>
        private string HandleOther(string requestContent)
        {
            string response = string.Empty;
            if (requestContent.Contains("你好") || requestContent.Contains("您好"))
            {
                response = "您也好~";
            }
            else
            {
                response = "我只能说,I am YZR";
            }

            return response;
        }
    }

这样就完成了关键字的消息回复了,当然,因为这里是我们自己的web服务器,我们可以进行更多的操作,比如查询天气,和数据库交互等

也许文本消息你玩腻了,那么下篇会和大家交流一下,事件的处理.

 

posted on 2015-11-25 23:39  巴夫巴夫  阅读(698)  评论(0编辑  收藏  举报