In the previous chapter, we have initially explained the basic principles of WeChat public account development. Today we will explore the design implementation.
First of all, we designed a module hierarchy diagram. Of course, the diagram only shows an implementation method and is not limited to this. See the figure below for details.
The main functions are introduced as follows:
1) Request interface layer. Processing HTTP requests and responses
2) Distribution layer. The request is passed in from the interface layer, and then the request type is analyzed specifically and distributed to different processors
3) Business logic layer. Here is our specific business logic. According to the request, the specific business logic is implemented.
4) Data layer. When we implement an application, we may need to access data, which can be a database or a file. If it is a simple application, this layer may not be available.
In fact, specific applications can be expanded on this structure, and the message object layer, business object layer, data access layer, functional management layer, etc. can be expanded. This is just to provide an idea and is not limited to this.
Design a flow chart based on the hierarchical diagram and describe each implementation process in detail. to understand the entire process. As shown in the figure below:
According to the flow chart, we can clearly understand the entire process and the specific implementation steps of message processing.
Below we implement the code for each process.
We need an HttpHandler or a web page to handle WeChat server HTTP requests.
Here we use HttpHandler. Because of its high flexibility and good performance.
The specific implementation is as follows.
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(); } }
If it is HTTPHandler, you need to configure the specific application in the configuration file. We will not explain the specific node configuration. Give an example directly and configure the HttpHandler node as follows
<httpHandlers> <add verb="*" path="WXService.ashx" type="namespace.WeiXinHttpHandler,WXWeb" validate="true"/></httpHandlers>
In order to encapsulate the function, we also encapsulated this in the processing component. In fact, it can be placed in HttpHandler.
1) Verify signature
If this is the first request, the signature needs to be verified. It is equivalent to an HTTP handshake. In the previous chapter, the server URL and token value were set. This function is to check whether the connection is successful.
This request is a GET request. The following specific instructions (official):
Business logic:
Encryption/verification process:
<1> Put the three parameters token, timestamp, and nonce into dictionary order Sorting
<2> Splice the three parameter strings into one string for SHA1 encryption
<3> The developer can compare the encrypted string with the signature to identify the The request came from WeChat
and the official only provided PHP code examples. Many things are not directly translated in C#. So there are also some specific treatments here. Let’s look at the official code first:
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; } }
We translate it into the C# version:
/// <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 encryption is required here. The specific algorithm is as follows:
/// <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) Distribution request
The next step is the specific message request, here are all POST requests.
Because there are multiple message types, we encapsulate them through factory classes, and then each message has a dedicated processor for processing. Specific implementation logic:
/// <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; }
The external method for processing requests (this is the method called by HttpHandler), that is:
/// <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) Message type
First let’s take a look , the specific message type, in fact, the message interface has been clearly given in the previous picture.
Let’s take a closer look here to see what types of messages are requested, what types of messages are replied, etc.
Be sure to note that the requested message is of text type, and the reply message is not necessarily text. It can be any replyable message such as graphics, text, music, etc. See the table below for details.
2) Design the message class according to the specific message interface.
这里给出类图,供参考。
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; } }
最后将处理结果返回至最初HttpHandler,响应给微信服务器,直接Response处理。这也是在最开始设计的HttpHandler中实现的。
下面是代码片段,具体可见一、Http请求
context.Response.Clear(); context.Response.Charset = "UTF-8"; context.Response.Write(responseMsg); context.Response.End();
更多微信公众平台开发教程(三) 基础框架搭建 相关文章请关注PHP中文网!