成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Koa2微信公眾號(hào)開(kāi)發(fā)之消息管理的示例分析

這篇文章將為大家詳細(xì)講解有關(guān)Koa2微信公眾號(hào)開(kāi)發(fā)之消息管理的示例分析,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

成都創(chuàng)新互聯(lián)公司成立與2013年,先為赤城等服務(wù)建站,赤城等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為赤城企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

接收消息

當(dāng)普通微信用戶向公眾賬號(hào)發(fā)消息時(shí),微信服務(wù)器將POST消息的XML數(shù)據(jù)包到開(kāi)發(fā)者填寫(xiě)的URL上。

接收普通消息數(shù)據(jù)格式

XML的結(jié)構(gòu)基本固定,不同的消息類(lèi)型略有不同。

用戶發(fā)送文本消息時(shí),微信公眾賬號(hào)接收到的XML數(shù)據(jù)格式如下所示:

<xml>
 <ToUserName><![CDATA[toUser]]></ToUserName>
 <FromUserName><![CDATA[fromUser]]></FromUserName>
 <CreateTime>createTime</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[this is a test]]></Content>
 <MsgId>1234567890123456</MsgId>
</xml>

用戶發(fā)送圖片消息時(shí),微信公眾賬號(hào)接收到的XML數(shù)據(jù)格式如下所示:

<xml> 
 <ToUserName><![CDATA[toUser]]></ToUserName>
 <FromUserName><![CDATA[fromUser]]></FromUserName>
 <CreateTime>1348831860</CreateTime> 
 <MsgType><![CDATA[image]]></MsgType> 
 <PicUrl><![CDATA[this is a url]]></PicUrl>
 <MediaId><![CDATA[media_id]]></MediaId> 
 <MsgId>1234567890123456</MsgId>
</xml>

其他消息消息類(lèi)型的結(jié)構(gòu)請(qǐng)查閱【微信公眾平臺(tái)開(kāi)發(fā)文檔】

對(duì)于POST請(qǐng)求的處理,koa2沒(méi)有封裝獲取參數(shù)的方法,需要通過(guò)自己解析上下文context中的原生node.js請(qǐng)求對(duì)象request。我們將用到row-body這個(gè)模塊來(lái)拿到數(shù)據(jù)。

先來(lái)優(yōu)化之前的代碼

這一節(jié)的代碼緊接著上一屆實(shí)現(xiàn)的代碼,在上一屆的基礎(chǔ)上輕微改動(dòng)了下。

'use strict'

const Koa = require('koa')
const app = new Koa()
const crypto = require('crypto')
// 將配置文件獨(dú)立到config.js
const config = require('./config')

app.use(async ctx => {
 // GET 驗(yàn)證服務(wù)器
 if (ctx.method === 'GET') {
  const { signature, timestamp, nonce, echostr } = ctx.query
  const TOKEN = config.wechat.token
  let hash = crypto.createHash('sha1')
  const arr = [TOKEN, timestamp, nonce].sort()
  hash.update(arr.join(''))
  const shasum = hash.digest('hex')
  if (shasum === signature) {
   return ctx.body = echostr
  }
  ctx.status = 401
  ctx.body = 'Invalid signature'
 } else if (ctx.method === 'POST') { // POST接收數(shù)據(jù)
  // TODO
 }
});

app.listen(7001);

這兒我們?cè)谥辉贕ET中驗(yàn)證了簽名值是否合法,實(shí)際上我們?cè)赑OST中也應(yīng)該驗(yàn)證簽名。

將簽名驗(yàn)證寫(xiě)成一個(gè)函數(shù)

function getSignature (timestamp, nonce, token) {
 let hash = crypto.createHash('sha1')
 const arr = [token, timestamp, nonce].sort()
 hash.update(arr.join(''))
 return hash.digest('hex')
}

優(yōu)化代碼,再POST中也加入驗(yàn)證

...

app.use(async ctx => {
 const { signature, timestamp, nonce, echostr } = ctx.query
 const TOKEN = config.wechat.token
 if (ctx.method === 'GET') {
  if (signature === getSignature(timestamp, nonce, TOKEN)) {
   return ctx.body = echostr
  }
  ctx.status = 401
  ctx.body = 'Invalid signature'
 }else if (ctx.method === 'POST') {
  if (signature !== getSignature(timestamp, nonce, TOKEN)) {
   ctx.status = 401
   return ctx.body = 'Invalid signature'
  }
  // TODO
 }
});
...

到這兒我們都沒(méi)有開(kāi)始實(shí)現(xiàn)接受XML數(shù)據(jù)包的功能,而是在修改之前的代碼。這是為了演示在實(shí)際開(kāi)發(fā)中的過(guò)程,寫(xiě)任何代碼都不是一步到位的,好的代碼都是改出來(lái)的。

2.3 接收公眾號(hào)普通消息的XML數(shù)據(jù)包

現(xiàn)在開(kāi)始進(jìn)入本節(jié)的重點(diǎn),接受XML數(shù)據(jù)包并轉(zhuǎn)為JSON

$ npm install raw-body --save
...
const getRawBody = require('raw-body')
...

// TODO
// 取原始數(shù)據(jù)
const xml = await getRawBody(ctx.req, {
 length: ctx.request.length,
 limit: '1mb',
 encoding: ctx.request.charset || 'utf-8'
});
console.log(xml)
return ctx.body = 'success' // 直接回復(fù)success,微信服務(wù)器不會(huì)對(duì)此作任何處理

給你的測(cè)試號(hào)發(fā)送文本消息,你可以在命令行看見(jiàn)打印出如下數(shù)據(jù)

<xml>
 <ToUserName><![CDATA[gh_9d2d49e7e006]]></ToUserName>
 <FromUserName><![CDATA[oBp2T0wK8lM4vIkmMTJfFpk6Owlo]]></FromUserName>
 <CreateTime>1516940059</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[JavaScript之禪]]></Content>
 <MsgId>6515207943908059832</MsgId>
</xml>

恭喜,到此你已經(jīng)可以接收到XML數(shù)據(jù)了。? 但是我們還需要將XML轉(zhuǎn)為JSON方便我們的使用,我們將用到xml2js這個(gè)包

$ npm install xml2js --save

我們需要寫(xiě)一個(gè)解析XML的異步函數(shù),返回一個(gè)Promise對(duì)象

function parseXML(xml) {
 return new Promise((resolve, reject) => {
  xml2js.parseString(xml, { trim: true, explicitArray: false, ignoreAttrs: true }, function (err, result) {
   if (err) {
    return reject(err)
   }
   resolve(result.xml)
  })
 })
}

接著調(diào)用parseXML方法,并打印出結(jié)果

...
const formatted = await parseXML(xml)
console.log(formatted)
return ctx.body = 'success'

一切正常的話*(實(shí)際開(kāi)發(fā)中你可能會(huì)遇到各種問(wèn)題)*,命令行將打印出如下JSON數(shù)據(jù)

{ ToUserName: 'gh_9d2d49e7e006',
 FromUserName: 'oBp2T0wK8lM4vIkmMTJfFpk6Owlo',
 CreateTime: '1516941086',
 MsgType: 'text',
 Content: 'JavaScript之禪',
 MsgId: '6515212354839473910' }

到此,我們就能處理微信接收到的消息了,你可以自己測(cè)試關(guān)注、取消關(guān)注、發(fā)送各種類(lèi)型的消息看看這個(gè)類(lèi)型的消息所對(duì)應(yīng)的XML數(shù)據(jù)格式都是怎么樣的

回復(fù)消息

當(dāng)用戶發(fā)送消息給公眾號(hào)時(shí)(或某些特定的用戶操作引發(fā)的事件推送時(shí)),會(huì)產(chǎn)生一個(gè)POST請(qǐng)求,開(kāi)發(fā)者可以在響應(yīng)包(Get)中返回特定XML結(jié)構(gòu),來(lái)對(duì)該消息進(jìn)行響應(yīng)(現(xiàn)支持回復(fù)文本、圖片、圖文、語(yǔ)音、視頻、音樂(lè))。嚴(yán)格來(lái)說(shuō),發(fā)送被動(dòng)響應(yīng)消息其實(shí)并不是一種接口,而是對(duì)微信服務(wù)器發(fā)過(guò)來(lái)消息的一次回復(fù)。

被動(dòng)回復(fù)用戶消息數(shù)據(jù)格式

前面說(shuō)了交互的數(shù)據(jù)格式為XML,接收消息是XML的,我們回復(fù)回去也應(yīng)該是XML。

微信公眾賬號(hào)回復(fù)用戶文本消息時(shí)的XML數(shù)據(jù)格式如下所示:

<xml> 
 <ToUserName><![CDATA[toUser]]></ToUserName> 
 <FromUserName><![CDATA[fromUser]]></FromUserName> 
 <CreateTime>12345678</CreateTime> 
 <MsgType><![CDATA[text]]></MsgType> 
 <Content><![CDATA[你好]]></Content> 
</xml>

微信公眾賬號(hào)回復(fù)用戶圖片消息時(shí)的XML數(shù)據(jù)格式如下所示:

<xml>
 <ToUserName><![CDATA[toUser]]></ToUserName>
 <FromUserName><![CDATA[fromUser]]></FromUserName>
 <CreateTime>12345678</CreateTime>
 <MsgType><![CDATA[image]]></MsgType>
 <Image><MediaId><![CDATA[media_id]]></MediaId></Image>
</xml>

篇幅所限就不一一列舉了,請(qǐng)查閱【微信公眾平臺(tái)開(kāi)發(fā)文檔】

前面的代碼都是直接回復(fù)success,不做任何處理。先來(lái)擼一個(gè)自動(dòng)回復(fù)吧。收到消息后就回復(fù)這兒是JavaScript之禪

// return ctx.body = 'success' // 直接success
ctx.type = 'application/xml'
return ctx.body = `<xml> 
<ToUserName><![CDATA[${formatted.FromUserName}]]></ToUserName> 
<FromUserName><![CDATA[${formatted.ToUserName}]]></FromUserName> 
<CreateTime>${new Date().getTime()}</CreateTime> 
<MsgType><![CDATA[text]]></MsgType> 
<Content><![CDATA[這兒是JavaScript之禪]]></Content> 
</xml>`

使用ejs模板引擎處理回復(fù)內(nèi)容

從這一小段代碼中可以看出,被動(dòng)回復(fù)消息就是把你想要回復(fù)的內(nèi)容按照約定的XML格式返回即可。但是一段一段的拼XML那多麻煩。我們來(lái)加個(gè)模板引擎方便我們處理XML。模板引擎有很多,ejs 是其中一種,它使用起來(lái)十分簡(jiǎn)單

首先下載并引入ejs

$ npm install ejs --save

如果你之前沒(méi)用過(guò)現(xiàn)在只需要記住下面這幾個(gè)語(yǔ)法,以及ejs.compile()方法

  1. <% code %>:運(yùn)行 JavaScript 代碼,不輸出

  2. <%= code %>:顯示轉(zhuǎn)義后的 HTML內(nèi)容

  3. <%- code %>:顯示原始 HTML 內(nèi)容

可以先看看這個(gè)ejs的小demo:

const ejs = require('ejs')
let tpl = `
<xml> 
 <ToUserName><![CDATA[<%-toUsername%>]]></ToUserName> 
 <FromUserName><![CDATA[<%-fromUsername%>]]></FromUserName> 
 <CreateTime><%=createTime%></CreateTime> 
 <MsgType><![CDATA[<%=msgType%>]]></MsgType> 
 <Content><![CDATA[<%-content%>]]></Content> 
</xml>
`
const compiled = ejs.compile(tpl)
let mess = compiled({
 toUsername: '1234',
 fromUsername: '12345',
 createTime: new Date().getTime(),
 msgType: 'text',
 content: 'JavaScript之禪',
})

console.log(mess)

/* 將打印出如下信息 
 *================
<xml>
 <ToUserName><![CDATA[1234]]></ToUserName>
 <FromUserName><![CDATA[12345]]></FromUserName>
 <CreateTime>1517037564494</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[JavaScript之禪]]></Content>
</xml>
*/

現(xiàn)在來(lái)編寫(xiě)被動(dòng)回復(fù)消息的模板,各種if else,這兒就直接貼代碼了

<xml>
 <ToUserName><![CDATA[<%-toUsername%>]]></ToUserName>
 <FromUserName><![CDATA[<%-fromUsername%>]]></FromUserName>
 <CreateTime><%=createTime%></CreateTime>
 <MsgType><![CDATA[<%=msgType%>]]></MsgType>
 <% if (msgType === 'news') { %>
 <ArticleCount><%=content.length%></ArticleCount>
 <Articles>
 <% content.forEach(function(item){ %>
 <item>
 <Title><![CDATA[<%-item.title%>]]></Title>
 <Description><![CDATA[<%-item.description%>]]></Description>
 <PicUrl><![CDATA[<%-item.picUrl || item.picurl || item.pic || item.thumb_url %>]]></PicUrl>
 <Url><![CDATA[<%-item.url%>]]></Url>
 </item>
 <% }); %>
 </Articles>
 <% } else if (msgType === 'music') { %>
 <Music>
 <Title><![CDATA[<%-content.title%>]]></Title>
 <Description><![CDATA[<%-content.description%>]]></Description>
 <MusicUrl><![CDATA[<%-content.musicUrl || content.url %>]]></MusicUrl>
 <HQMusicUrl><![CDATA[<%-content.hqMusicUrl || content.hqUrl %>]]></HQMusicUrl>
 </Music>
 <% } else if (msgType === 'voice') { %>
 <Voice>
 <MediaId><![CDATA[<%-content.mediaId%>]]></MediaId>
 </Voice>
 <% } else if (msgType === 'image') { %>
 <Image>
 <MediaId><![CDATA[<%-content.mediaId%>]]></MediaId>
 </Image>
 <% } else if (msgType === 'video') { %>
 <Video>
 <MediaId><![CDATA[<%-content.mediaId%>]]></MediaId>
 <Title><![CDATA[<%-content.title%>]]></Title>
 <Description><![CDATA[<%-content.description%>]]></Description>
 </Video>
 <% } else { %>
 <Content><![CDATA[<%-content%>]]></Content>
 <% } %>
</xml>

現(xiàn)在就可以使用我們寫(xiě)好的模板回復(fù)XML消息了

...
const formatted = await parseXML(xml)
console.log(formatted)
let info = {}
let type = 'text'
info.msgType = type
info.createTime = new Date().getTime()
info.toUsername = formatted.FromUserName
info.fromUsername = formatted.ToUserName
info.content = 'JavaScript之禪'
return ctx.body = compiled(info)

我們可以把這個(gè)回復(fù)消息的功能寫(xiě)成一個(gè)函數(shù)

function reply (content, fromUsername, toUsername) {
 var info = {}
 var type = 'text'
 info.content = content || ''
 // 判斷消息類(lèi)型
 if (Array.isArray(content)) {
  type = 'news'
 } else if (typeof content === 'object') {
  if (content.hasOwnProperty('type')) {
   type = content.type
   info.content = content.content
  } else {
   type = 'music'
  }
 }
 info.msgType = type
 info.createTime = new Date().getTime()
 info.toUsername = toUsername
 info.fromUsername = fromUsername
 return compiled(info)
}

在回復(fù)消息的時(shí)候直接調(diào)用這個(gè)方法即可

...
const formatted = await parseXML(xml)
console.log(formatted)
const content = 'JavaScript之禪'
const replyMessageXml = reply(content, formatted.ToUserName, formatted.FromUserName)
return ctx.body = replyMessageXml

現(xiàn)在為了測(cè)試我們所寫(xiě)的這個(gè)功能,來(lái)實(shí)現(xiàn)一個(gè)【學(xué)我說(shuō)話】的功能:

回復(fù)音樂(lè)將返回一個(gè)音樂(lè)類(lèi)型的消息,回復(fù)文本圖片,語(yǔ)音,公眾號(hào)將返回同樣的內(nèi)容,當(dāng)然了你可以在這個(gè)基礎(chǔ)上進(jìn)行各種發(fā)揮。

....
const formatted = await parseXML(xml)
console.log(formatted)
let content = ''
if (formatted.Content === '音樂(lè)') {
 content = {
  type: 'music',
  content: {
   title: 'Lemon Tree',
   description: 'Lemon Tree',
   musicUrl: 'http://mp3.com/xx.mp3'
  },
 }
} else if (formatted.MsgType === 'text') {
 content = formatted.Content
} else if (formatted.MsgType === 'image') {
 content = {
  type: 'image',
  content: {
   mediaId: formatted.MediaId
  },
 }
} else if (formatted.MsgType === 'voice') {
 content = {
  type: 'voice',
  content: {
   mediaId: formatted.MediaId
  },
 }
} else {
 content = 'JavaScript之禪'
}
const replyMessageXml = reply(content, formatted.ToUserName, formatted.FromUserName)
console.log(replyMessageXml)
ctx.type = 'application/xml'
return ctx.body = replyMessageXml

nice,到此時(shí)我們的測(cè)試號(hào)已經(jīng)能夠根據(jù)我們的消息做出相應(yīng)的回應(yīng)了

Koa2微信公眾號(hào)開(kāi)發(fā)之消息管理的示例分析

關(guān)于“Koa2微信公眾號(hào)開(kāi)發(fā)之消息管理的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

網(wǎng)頁(yè)題目:Koa2微信公眾號(hào)開(kāi)發(fā)之消息管理的示例分析
URL網(wǎng)址:http://jinyejixie.com/article12/pddpgc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)網(wǎng)站建設(shè)、ChatGPT、動(dòng)態(tài)網(wǎng)站、Google網(wǎng)站導(dǎo)航、網(wǎng)站排名

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

小程序開(kāi)發(fā)
萨嘎县| 越西县| 兴安盟| 乌兰察布市| 县级市| 海口市| 孟连| 同心县| 清徐县| 双鸭山市| 翁牛特旗| 文水县| 且末县| 谢通门县| 新晃| 福建省| 兖州市| 循化| 寿光市| 专栏| 临夏市| 舒兰市| 汕尾市| 大厂| 茶陵县| 商南县| 南安市| 喜德县| 故城县| 邵武市| 江北区| 巴林右旗| 韶山市| 浏阳市| 旺苍县| 壤塘县| 白玉县| 徐闻县| 弋阳县| 泰宁县| 丰宁|