I’ve always wanted to add more travel logs or daily notes to the log, but there are really no entertainment options in winter, and today, with the outbreak of the Novel Coronavirus, the entertainment industry is basically at a standstill, so let’s just keep typing code… In fact, is also the so-called knock code, admire their self-discipline, always unconsciously place to open Steam……

These days, I have been improving and optimizing my public account. Now I can continue to update a development record about the customized passive response.

Official document intercepts

Passive reply User messages are divided into the following six reply types. We need to return the required reply types to the server as fixed strings in accordance with the official API. The following are the different types and their corresponding strings:

  • Reply text message
<xml> <ToUserName><! [CDATA[toUser]]></ToUserName> <FromUserName><! [CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><! [CDATA[text]]></MsgType> <Content><! [CDATA[hello]]></Content> </ XML >Copy the code

parameter

Whether must describe

ToUserName

is

Recipient account (OpenID received)

FromUserName is

Developer wechat account

CreateTime

is

Message creation time (integer)

MsgType

is

The message type is text

Content

is

Message content of the reply (line break: line break can be used in content, wechat client supports line break display)
  • Reply to picture message
<xml> <ToUserName><! [CDATA[toUser]]></ToUserName> <FromUserName><! [CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><! [CDATA[image]]></MsgType> <Image> <MediaId><! [CDATA[media_id]]></MediaId> </Image> </xml>Copy the code

parameter

Whether must instructions

ToUserName

is

Recipient account (OpenID received)

FromUserName is

Developer wechat account

CreateTime

is

Message creation time (integer)

MsgType

is

The message type is image

MediaId

is

Id obtained by uploading multimedia files through the interface in the material management
  • Reply to a Voice Message
<xml> <ToUserName><! [CDATA[toUser]]></ToUserName> <FromUserName><! [CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><! [CDATA[voice]]></MsgType> <Voice> <MediaId><! [CDATA[media_id]]></MediaId> </Voice> </xml>Copy the code

parameter

Whether must instructions

ToUserName

is

Recipient account (OpenID received)

FromUserName is

Developer wechat account

CreateTime

is

Message creation timestamp (integer)

MsgType

is

The message type is Voice

MediaId

is

Id obtained by uploading multimedia files through the interface in the material management
  • Reply to video messages
<xml> <ToUserName><! [CDATA[toUser]]></ToUserName> <FromUserName><! [CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><! [CDATA]></MsgType> <Video> <MediaId><! [CDATA[media_id]]></MediaId> <Title><! [CDATA[title]]></Title> <Description><! [CDATA[description]]></Description> </Video> </xml>Copy the code

parameter

Whether must instructions

ToUserName

is

Recipient account (OpenID received)

FromUserName is

Developer wechat account

CreateTime

is

Message creation time (integer)

MsgType

is

The message type is Video

MediaId

is

Id obtained by uploading multimedia files through the interface in the material management
Title

no

Title of the video message

Description

no

Description of the video message

  • Reply to music messages
<xml> <ToUserName><! [CDATA[toUser]]></ToUserName> <FromUserName><! [CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><! [CDATA[music]]></MsgType> <Music> <Title><! [CDATA[TITLE]]></Title> <Description><! [CDATA[DESCRIPTION]]></Description> <MusicUrl><! [CDATA[MUSIC_Url]]></MusicUrl> <HQMusicUrl><! [CDATA[HQ_MUSIC_Url]]></HQMusicUrl> <ThumbMediaId><! [CDATA[media_id]]></ThumbMediaId> </Music> </xml>Copy the code

parameter

Whether must instructions

ToUserName

is

Recipient account (OpenID received)

FromUserName is

Developer wechat account

CreateTime

is

Message creation time (integer)

MsgType

is

The message type is music

Title

no

Music title

Description

no

Music to describe

MusicURL

no

Music links

HQMusicUrl

no

High quality music link, WIFI environment preferentially use this link to play music

ThumbMediaId is

The media ID of the thumbnail, obtained by uploading the multimedia file through the interface in the Material management
  • Reply to graphic message
<xml> <ToUserName><! [CDATA[toUser]]></ToUserName> <FromUserName><! [CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><! [CDATA[news]]></MsgType> <ArticleCount>1</ArticleCount> <Articles> <item> <Title><! [CDATA[title1]]></Title> <Description><! [CDATA[description1]]></Description> <PicUrl><! [CDATA[picurl]]></PicUrl> <Url><! [CDATA[url]]></Url> </item> </Articles> </xml>Copy the code

parameter

Whether must instructions

ToUserName

is

Recipient account (OpenID received)

FromUserName is

Developer wechat account

CreateTime

is

Message creation time (integer)

MsgType

is

The message type is news

ArticleCount is

Number of text and text messages; When a user sends a text message, an image, a video message, a text message, or a location message, the developer can only reply to one text message. In other scenarios, a maximum of eight text messages can be replied
Articles

is

Note that if the number of messages exceeds the limit, only the number of messages within the limit will be sent
Title

is

Text message title

Description

is

Text message description

PicUrl

is

Image link, support JPG, PNG format, better effect for large picture 360200. Small picture 200200
Url

is

Click the text message jump link

xml2js

Xml2js is a simple XML-to-javascript object converter that is officially used as follows:

var parseString = require('xml2js').parseString; var xml = "<root>Hello xml2js! </root>" parseString(xml, function (err, result) { console.dir(result); });Copy the code

More usage, also please give walk only www.npmjs.com/package/xml…

Node.js custom passive reply development

First, we need to configure routes to receive requests and data from the server.

App.post ("/", (req,res, next)=> {... })Copy the code

You need to use event listeners to monitor and control data;

App.post ("/", (req,res, next)=> {var buffer = [] req.on('data', (data) => { buffer.push(data) }) req.on('end', Var msgXml = buffer.concat (Buffer).toString(' utF-8 ')})})Copy the code

We first stored the binary data returned by wechat in the buffer array, and processed it into common XML data at the end of the request.

The problem is that Node.js can’t convert XML directly into Javascript objects, so we need the xml2js component to do this for us;

Var reply = require('./reply') req.on('end', () => {// convert data to UTF-8 format var msgXml = buffer.concat (Buffer).tostring (' utF-8 ') // Call parseString method of XML2JS module parseString(msgXml, { explicitArray: false }, (error, If (error) {console.log(error) return} result = result. XML // result. XML is the real data retrieved Reply (result, (resultXml) => {// Invoke the reply function res.send(resultXml)})})})......Copy the code

Result.xml, which contains ToUserName, FromUserName, etc…

There is one pit to watch out for!! Attention!!!!! Attention! Important things three times: The corresponding relationship of ToUserName and FromUserName obtained here is opposite to that of ToUserName and FromUserName in the submitted template. Result.xml. ToUserName should correspond to template data FromUserName, while result.xml.FromUserName corresponds to template data ToUserName.

In addition to the above part that needs to be added into app.js, I made two scripts for processing the reply function separately, namely reply.js and replytype. js. Replytype. js stores all involved templates. Assist reply.js to customize the reply;

Here’s the code in replytype.js:

Var request = require('./request') var request = require('./request') var request = require('./request') content) => { console.log('reply type text ! ') var xmlContent = '<xml><ToUserName><! [CDATA[' + result.FromUserName + ']]></ToUserName>' xmlContent += '<FromUserName><! [CDATA[' + result.ToUserName + ']]></FromUserName>' xmlContent += '<CreateTime>' + new Date().getTime() + '</CreateTime>' xmlContent += '<MsgType><! [CDATA[text]]></MsgType>' xmlContent += '<Content><! [CDATA[' + content + ']]></ content ></ XML >' return xmlContent} // exports.imgMsg = function (result, urlPath) callback) { uploadFile(urlPath, 'image').then((media_id) => { console.log('reply type image ! ', media_id) var xmlContent = '<xml><ToUserName><! [CDATA[' + result.FromUserName + ']]></ToUserName>' xmlContent += '<FromUserName><! [CDATA[' + result.ToUserName + ']]></FromUserName>' xmlContent += '<CreateTime>' + new Date().getTime() + '</CreateTime>' xmlContent += '<MsgType><! [CDATA[image]]></MsgType>' xmlContent += '<Image><MediaId><! [CDATA[' + media_id + ']]></MediaId></Image></ XML >' callback(xmlContent)})} // Echo exports.graphicmsg = (result, contentArr) => { console.log('reply type image and text ! ') var xmlContent = '<xml><ToUserName><! [CDATA[' + result.FromUserName + ']]></ToUserName>' xmlContent += '<FromUserName><! [CDATA[' + result.ToUserName + ']]></FromUserName>' xmlContent += '<CreateTime>' + new Date().getTime() + '</CreateTime>' xmlContent += '<MsgType><! [CDATA[news]]></MsgType>' xmlContent += '<ArticleCount>' + contentArr.length + '</ArticleCount>' xmlContent += '<Articles>' contentArr.map((item, index) => { xmlContent += '<item>' xmlContent += '<Title><! [CDATA[' + item.Title + ']]></Title>' xmlContent += '<Description><! [CDATA[' + item.Description + ']]></Description>' xmlContent += '<PicUrl><! [CDATA[' + item.PicUrl + ']]></PicUrl>' xmlContent += '<Url><! [CDATA[' + item.Url + ']]></Url>' xmlContent += '</item>' }) xmlContent += '</Articles></xml>' return xmlContent }Copy the code

As the image reply template in the above code needs to obtain media_id, it cannot be used independently in the development process. It needs to obtain the permission to use the material of the public account, that is, the uploadFile method in the above code, which I will explain later

All of the above code uses asynchronous functions except for simple text replies, so here we use callback methods to throw the final template to reply.js

Here’s another pitfall, where graphic replies have been restricted for some reason:

  • A passive reply can reply to only one text message
  • For the development of the public number (not the operation of the public number background operation and maintenance), passive response can not use the big picture, size map contrast figure

Replytype.js introduces the reply.js page as follows:

  • The picture reply
Join (__dirname, 'custom image.jpg ') resultXml = replyType.imgMsg(result, urlPath, (resultXml) => { callback(resultXml) })Copy the code

  • Text response
TextMsg (result, 'reply content ') callback(resultXml)Copy the code

  • By reply
ResultXml = replyType.graphicMsg(result, contentArr) // contentArr is an array objectCopy the code

Use custom replies

Result. XML mentioned above not only contains ToUserName and FromUserName, but also contains user operation information:

  • result.xml.MsgType === 'event'Indicates that a user event triggers, such as
    • result.xml.Event === 'subscribe'Represents the user pays attention
    • result.xml.Event === 'CLICK'Indicates that the user operates through a custom menu item
      • result.xml.EventKeyYou can get a custom menukeyattribute
  • result.xml.MsgType === 'text'Note The user is triggered by entering keywords
    • result.xml.ContentGet the details of what the user entered

Upload the material and get the media_id

The materials here can be pictures, voice, etc. The official instructions are as follows:

  • Request mode: POST
  • Request address: https://api.weixin.qq.com/cgi-bin/media/upload?accesstoken=ACCESSTOKEN&type=TYPE
Media_id function uploadFile (urlPath, type) {return new Promise(resolve, reject) => { fs.readFile('./config.json', 'utf-8', (error, Data) => {if (error) {console.log('uploadFile read accessToken fail', error) return} var form = {// Create form media: fs.createReadStream(urlPath) } var url = 'https://api.weixin.qq.com/cgi-bin/media/upload?access_token=' + JSON.parse(data).setAccessToken.accessToken + '&type=' + type request.post(url, form).then((result) => { resolve(JSON.parse(result).media_id) }) }) }) }Copy the code

My access_token is saved in config.json, so I first get it through fs.readFile, and then join the interface. The type in the interface is the temporary media file type that needs to be created. There are image, voice, video and thumb, which are mainly used for video and music formats.

Fs.createreadstream is used to get the file stream of the media file. Send a public id to the file stream in the form of the requested parameter. The server will return a string that is the media_id of the media file

That’s all for the notes on custom replies.

My data came from my blog site. At first, I used the WP-JSON interface file provided by WordPress, but later I modified the way of obtaining the interface for security reasons. At present, the data of my official account is obtained from the crawl site, and I will share the learning record about the Node crawl site later.

Still hope each guest officer can like!

The article has been synchronized with my personal blog: “Node wechat Public Account Development Custom Menu”.

Related articles:

  • Node wechat public account development access public account
  • Node wechat public account is developed to encapsulate request and obtain access_token
  • Node wechat public account development custom menu

Reference:

  • [official document of wechat Official Account]
  • [wechat public platform interface debugging tool]
  • [wechat public platform test account]
  • [Node develops wechat public account (1) — access wechat public account]
  • [Node develops wechat public account (2) — wechat reply]
  • [Node develops wechat public account (3) — wechat menu]
  • [Node develops wechat public account (4) — upload material]

This article is published by OpenWrite!