微信公众号被动回复方案梳理

微信公众号机器人客服回复方案预梳理

一、微信公众平台开发接入指南

接入微信公众平台开发,需要按照如下步骤完成:

1、填写服务器配置

登录微信公众平台官网后,在公众平台后台管理页面 - 开发者中心页,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件的接口URL。Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。

2、验证服务器地址的有效性

开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带四个参数:

参数

描述

signature

微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。

timestamp

时间戳

nonce

随机数

echostr

随机字符串

 

3、依据接口文档实现业务逻辑

验证URL有效性成功后即接入生效,成为开发者。如果公众号类型为服务号(订阅号只能使用普通消息接口),可以在公众平台网站中申请认证,认证成功的服务号将获得众多接口权限,以满足开发者需求。此后用户每次向公众号发送消息、或者产生自定义菜单点击事件时,开发者填写的服务器配置URL将得到微信服务器推送过来的消息和事件,然后开发者可以依据自身业务逻辑进行响应,例如回复消息等。公众号调用各接口时,一般会获得正确的结果,具体结果可见对应接口的说明。返回错误时,可根据返回码来查询错误原因。全局返回码说明用户向公众号发送消息时,公众号方收到的消息发送者是一个OpenID,是使用用户微信号加密后的结果,每个用户对每个公众号有一个唯一的OpenID。

三、微信服务器向公众号服务器推送消息的类型

当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。

微信服务器在将用户的消息发给公众号的开发者服务器地址(开发者中心处配置)后,微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次,如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。关于重试的消息排重,有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime 排重。

微信服务器推送消息类型的XML数据包结构

文本消息

 

 

 

 1348831860

 

 

 1234567890123456

 

参数

描述

ToUserName

开发者微信号

FromUserName

发送方帐号(一个OpenID)

CreateTime

消息创建时间 (整型)

MsgType

text

Content

文本消息内容

MsgId

消息id,64位整型

图片消息

 

 

 

 1348831860

 

 

 

 1234567890123456

 

参数

描述

ToUserName

开发者微信号

FromUserName

发送方帐号(一个OpenID)

CreateTime

消息创建时间 (整型)

MsgType

image

PicUrl

图片链接

MediaId

图片消息媒体id,可以调用多媒体文件下载接口拉取数据。

MsgId

消息id,64位整型

 

语音消息

1357290913

1234567890123456

参数

描述

ToUserName

开发者微信号

FromUserName

发送方帐号(一个OpenID)

CreateTime

消息创建时间 (整型)

MsgType

语音为voice

MediaId

语音消息媒体id,可以调用多媒体文件下载接口拉取数据。

Format

语音格式,如amr,speex等

MsgID

消息id,64位整型

 

请注意,开通语音识别后,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,增加一个Recongnition字段(注:由于客户端缓存,开发者开启或者关闭语音识别功能,对新关注者立刻生效,对已关注用户需要24小时生效。开发者可以重新关注此帐号进行测试)。开启语音识别后的语音XML数据包如下:

1357290913

1234567890123456

多出的字段中,Format为语音格式,一般为amr,Recognition为语音识别结果,使用UTF8编码。

视频消息

1357290913

1234567890123456

参数

描述

ToUserName

开发者微信号

FromUserName

发送方帐号(一个OpenID)

CreateTime

消息创建时间 (整型)

MsgType

视频为video

MediaId

视频消息媒体id,可以调用多媒体文件下载接口拉取数据。

ThumbMediaId

视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。

MsgId

消息id,64位整型

小视频消息

1357290913

1234567890123456

参数

描述

ToUserName

开发者微信号

FromUserName

发送方帐号(一个OpenID)

CreateTime

消息创建时间 (整型)

MsgType

小视频为shortvideo

MediaId

视频消息媒体id,可以调用多媒体文件下载接口拉取数据。

ThumbMediaId

视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。

MsgId

消息id,64位整型

地理位置消息

1351776360

23.134521

113.358803

20

1234567890123456

参数

描述

ToUserName

开发者微信号

FromUserName

发送方帐号(一个OpenID)

CreateTime

消息创建时间 (整型)

MsgType

location

Location_X

地理位置维度

Location_Y

地理位置经度

Scale

地图缩放大小

Label

地理位置信息

MsgId

消息id,64位整型

链接消息

1351776360

<![CDATA[公众平台官网链接]]>

1234567890123456

参数

描述

ToUserName

接收方微信号

FromUserName

发送方微信号,若为普通用户,则是一个OpenID

CreateTime

消息创建时间

MsgType

消息类型,link

Title

消息标题

Description

消息描述

Url

消息链接

MsgId

消息id,64位整型

 

示例代码Java版)

首先接收微信服务器POST请求数据, 代码如下:接收微信服务器POST请求数据, 代码如下:

1. /** 

2.  * 微信公众平台 所有接口入口 

3.  *  

4.  * @param request 

5.  *            the request send by the client to the server 

6.  * @param response 

7.  *            the response send by the server to the client 

8.  * @throws ServletException 

9.  *             if an error occurred 

10.  * @throws IOException 

11.  *             if an error occurred 

12.  */  

13.  public void doPost(HttpServletRequest request, HttpServletResponse response)  

14.         throws ServletException, IOException {  

15.     response.setCharacterEncoding("UTF-8");  

16.     request.setCharacterEncoding("UTF-8");  

17.     PrintWriter out = response.getWriter();  

18.     try {  

19.         InputStream is = request.getInputStream();  

20.         PushManage push = new PushManage();  

21.         String getXml = push.PushManageXml(is);  

22.         out.print(getXml);  

23.     } catch (JDOMException e) {  

24.         e.printStackTrace();  

25.         out.print("");  

26.     } catch (Exception e) {  

27.         out.print("");  

28.     } finally {   

29.         if(out!=null) {   

30.             out.flush();  

31.             out.close();  

32.         }  

33.     }  

34. }  

 

四、被动回复用户消息格式

假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示。详见下面说明:

1、(推荐方式)直接回复success

2、直接回复空串(指字节长度为0的空字符串,而不是XML结构体中content字段的内容为空)

回复文本消息

12345678

参数

是否必须

描述

ToUserName

接收方帐号(收到的OpenID)

FromUserName

开发者微信号

CreateTime

消息创建时间 (整型)

MsgType

text

Content

回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示)

 

回复图片消息

12345678

参数

是否必须

说明

ToUserName

接收方帐号(收到的OpenID)

FromUserName

开发者微信号

CreateTime

消息创建时间 (整型)

MsgType

image

MediaId

通过素材管理接口上传多媒体文件,得到的id。

 

 

 

回复语音消息

12345678

参数

是否必须

说明

ToUserName

接收方帐号(收到的OpenID)

FromUserName

开发者微信号

CreateTime

消息创建时间戳 (整型)

MsgType

语音,voice

MediaId

通过素材管理接口上传多媒体文件,得到的id

 

 

 

 

 

回复视频消息

12345678

<![CDATA[title]]>

参数

是否必须

说明

ToUserName

接收方帐号(收到的OpenID)

FromUserName

开发者微信号

CreateTime

消息创建时间 (整型)

MsgType

video

MediaId

通过素材管理接口上传多媒体文件,得到的id

Title

视频消息的标题

Description

视频消息的描述

 

 

 

 

 

 

回复音乐消息

12345678

<![CDATA[TITLE]]>

参数

是否必须

说明

ToUserName

接收方帐号(收到的OpenID)

FromUserName

开发者微信号

CreateTime

消息创建时间 (整型)

MsgType

music

Title

音乐标题

Description

音乐描述

MusicURL

音乐链接

HQMusicUrl

高质量音乐链接,WIFI环境优先使用该链接播放音乐

ThumbMediaId

缩略图的媒体id,通过素材管理接口上传多媒体文件,得到的id

 

 

 

 

 

 

 

回复图文消息

12345678

2

<![CDATA[title1]]>

<![CDATA[title]]>

参数

是否必须

说明

ToUserName

接收方帐号(收到的OpenID)

FromUserName

开发者微信号

CreateTime

消息创建时间 (整型)

MsgType

news

ArticleCount

图文消息个数,限制为10条以内

Articles

多条图文消息信息,默认第一个item为大图,注意,如果图文数超过10,则将会无响应

Title

图文消息标题

Description

图文消息描述

PicUrl

图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200

Url

点击图文消息跳转链接

 

 

 

 

 

 

根据POST请求的XML数据解析并响应相关信息,代码如下

1. package cn.wuzhuti.weixin.utils;  

2.   

3. import java.io.IOException;  

4. import java.io.InputStream;  

5. import java.text.SimpleDateFormat;  

6. import java.util.Date;  

7. import java.util.List;  

8. import org.jdom2.Document;  

9. import org.jdom2.Element;  

10. import org.jdom2.JDOMException;  

11. import org.jdom2.input.SAXBuilder;  

12. import org.jdom2.output.XMLOutputter;  

13.   

14. public class PushManage {  

15.       

16.     public String PushManageXml(InputStream is) throws JDOMException {  

17.   

18.         String returnStr = ""// 反回Servlet字符串  

19.         String toName = ""// 开发者微信号  

20.         String fromName = ""// 发送方帐号(一个OpenID)  

21.         String type = ""// 请求类型  

22.         String con = ""// 消息内容(接收)  

23.         String event = ""// 自定义按钮事件请求  

24.         String eKey = ""// 事件请求key值  

25.           

26.         try {  

27.   

28.             SAXBuilder sax = new SAXBuilder();  

29.             Document doc = sax.build(is);  

30.             // 获得文件的根元素  

31.             Element root = doc.getRootElement();  

32.   

33.             // 获得根元素的第一级子节点  

34.             List list = root.getChildren();  

35.             for (int j = 0; j < list.size(); j++) {  

36.                 // 获得结点  

37.                 Element first = (Element) list.get(j);  

38.   

39.                 if (first.getName().equals("ToUserName")) {  

40.                     toName = first.getValue().trim();  

41.                 } else if (first.getName().equals("FromUserName")) {  

42.                     fromName = first.getValue().trim();  

43.                 } else if (first.getName().equals("MsgType")) {  

44.                     type = first.getValue().trim();  

45.                 } else if (first.getName().equals("Content")) {  

46.                     con = first.getValue().trim();  

47.                 } else if (first.getName().equals("Event")) {  

48.                     event = first.getValue().trim();  

49.                 } else if (first.getName().equals("EventKey")) {  

50.                     eKey = first.getValue().trim();  

51.                 }  

52.             }  

53.         } catch (IOException e) {  

54.             //异常  

55.         }  

56.           

57.         if (type.equals("event")) {     //此为事件  

58.             if (event.equals("subscribe")) {// 此为 关注事件  

59.                   

60.             } else if (event.equals("unsubscribe")) { //此为取消关注事件   

61.                   

62.             } else if (event.equals("CLICK")) { //此为 自定义菜单按钮点击事件  

63.                 // 以下为自定义按钮事件  

64.                 if (eKey.equals("V1")) { //菜单1  

65.                     returnStr = getBackXMLTypeText(toName,fromName,"点击了菜单1");  

66.                 } else if (eKey.equals("V2")) {    //菜单2  

67.                     returnStr = getBackXMLTypeText(toName,fromName,"点击了菜单2");  

68.                 }  

69.             }  

70.         } else if (type.equals("text")) { // 此为 文本信息  

71.             returnStr = getBackXMLTypeText(toName,fromName,"输入了:"+con);  

72.         }   

73.           

74.         return returnStr;  

75.     }  

76.       

77.   

78.     /** 

79.      * 编译文本信息 

80.      *  

81.      * @author xiaowu 

82.      * @since 2013-9-27 

83.      * @param toName 

84.      * @param FromName 

85.      * @param content 

86.      * @return 

87.      */  

88.     private String getBackXMLTypeText(String toName, String fromName,  

89.             String content) {  

90.   

91.         String returnStr = "";  

92.   

93.         SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");  

94.         String times = format.format(new Date());  

95.   

96.         Element rootXML = new Element("xml");  

97.   

98.         rootXML.addContent(new Element("ToUserName").setText(fromName));  

99.         rootXML.addContent(new Element("FromUserName").setText(toName));  

100.         rootXML.addContent(new Element("CreateTime").setText(times));  

101.         rootXML.addContent(new Element("MsgType").setText("text"));  

102.         rootXML.addContent(new Element("Content").setText(content));  

103.   

104.         Document doc = new Document(rootXML);  

105.   

106.         XMLOutputter XMLOut = new XMLOutputter();  

107.         returnStr = XMLOut.outputString(doc);  

108.   

109.         return returnStr;  

110.     }  

111.   

112.     /** 

113.      * 编译图片信息(单图模式) 

114.      *  

115.      * @author xiaowu 

116.      * @since 2013-9-27 

117.      * @param toName 

118.      * @param FromName 

119.      * @param content 

120.      * @return 

121.      */  

122.     private String getBackXMLTypeImg(String toName, String fromName,  

123.             String title, String content, String url, String pUrl) {  

124.   

125.         String returnStr = "";  

126.   

127.         SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");  

128.         String times = format.format(new Date());  

129.   

130.         Element rootXML = new Element("xml");  

131.   

132.         rootXML.addContent(new Element("ToUserName").setText(fromName));  

133.         rootXML.addContent(new Element("FromUserName").setText(toName));  

134.         rootXML.addContent(new Element("CreateTime").setText(times));  

135.         rootXML.addContent(new Element("MsgType").setText("news"));  

136.         rootXML.addContent(new Element("ArticleCount").setText("1"));  

137.   

138.         Element fXML = new Element("Articles");  

139.         Element mXML = null;  

140.   

141.         mXML = new Element("item");  

142.         mXML.addContent(new Element("Title").setText(title));  

143.         mXML.addContent(new Element("Description").setText(content));  

144.         mXML.addContent(new Element("PicUrl").setText(pUrl));  

145.         mXML.addContent(new Element("Url").setText(url));  

146.         fXML.addContent(mXML);  

147.         rootXML.addContent(fXML);  

148.   

149.         Document doc = new Document(rootXML);  

150.   

151.         XMLOutputter XMLOut = new XMLOutputter();  

152.         returnStr = XMLOut.outputString(doc);  

153.   

154.         return returnStr;  

155.     }  

156.     /** 

157.      * 编译图片信息(无图模式) 

158.      *  

159.      * @author xiaowu 

160.      * @since 2013-9-27 

161.      * @param toName 

162.      * @param FromName 

163.      * @param content 

164.      * @return 

165.      */  

166.     private String getBackXMLTypeImg(String toName, String fromName,  

167.             String title, String content, String url) {  

168.   

169.         String returnStr = "";  

170.   

171.         SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");  

172.         String times = format.format(new Date());  

173.   

174.         Element rootXML = new Element("xml");  

175.   

176.         rootXML.addContent(new Element("ToUserName").setText(fromName));  

177.         rootXML.addContent(new Element("FromUserName").setText(toName));  

178.         rootXML.addContent(new Element("CreateTime").setText(times));  

179.         rootXML.addContent(new Element("MsgType").setText("news"));  

180.         rootXML.addContent(new Element("ArticleCount").setText("1"));  

181.   

182.         Element fXML = new Element("Articles");  

183.         Element mXML = null;  

184.   

185.         //String url = "";  

186.         String ss = "";  

187.         mXML = new Element("item");  

188.         mXML.addContent(new Element("Title").setText(title));  

189.         mXML.addContent(new Element("Description").setText(content));  

190.         mXML.addContent(new Element("PicUrl").setText(ss));  

191.         mXML.addContent(new Element("Url").setText(url));  

192.         fXML.addContent(mXML);  

193.         rootXML.addContent(fXML);  

194.   

195.         Document doc = new Document(rootXML);  

196.   

197.         XMLOutputter XMLOut = new XMLOutputter();  

198.         returnStr = XMLOut.outputString(doc);  

199.   

200.         return returnStr;  

201.     }  

202.   

203.     /** 

204.      * 编译音乐信息 

205.      *  

206.      * @author xiaowu 

207.      * @since 2013-9-27 

208.      * @param toName 

209.      * @param FromName 

210.      * @param content 

211.      * @return 

212.      */  

213.     @SuppressWarnings("unused")  

214.     private String getBackXMLTypeMusic(String toName, String fromName,  

215.             String content) {  

216.   

217.         String returnStr = "";  

218.   

219.         SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");  

220.         String times = format.format(new Date());  

221.   

222.         Element rootXML = new Element("xml");  

223.   

224.         rootXML.addContent(new Element("ToUserName").setText(fromName));  

225.         rootXML.addContent(new Element("FromUserName").setText(toName));  

226.         rootXML.addContent(new Element("CreateTime").setText(times));  

227.         rootXML.addContent(new Element("MsgType").setText("music"));  

228.   

229.         Element mXML = new Element("Music");  

230.   

231.         mXML.addContent(new Element("Title").setText("音乐"));  

232.         mXML.addContent(new Element("Description").setText("音乐让人心情舒畅!"));  

233.         mXML.addContent(new Element("MusicUrl").setText(content));  

234.         mXML.addContent(new Element("HQMusicUrl").setText(content));  

235.   

236.         rootXML.addContent(mXML);  

237.   

238.         Document doc = new Document(rootXML);  

239.   

240.         XMLOutputter XMLOut = new XMLOutputter();  

241.         returnStr = XMLOut.outputString(doc);  

242.   

243.         return returnStr;  

244.     }  

245. }  

 

你可能感兴趣的:(微信公众号被动回复方案梳理)