微信公众号开发

文章目录

    • 一、微信公众号简介
    • 二、注册/登录微信公众号
    • 三、功能介绍
      • 1、编辑模式(个人开发者,无需服务器)
      • 2、开发模式
    • 四、实战开发
      • 1、配置服务器
      • 2、模块化
    • 五、获取 access_token
      • 1、access_token 是什么?
      • 2、获取 access_token 功能实现
    • 六、自动回复功能
      • 1、准备工作
      • 2、代码实现
    • 七、自定义菜单
    • 八、微信中的网页开发
      • 1、简单实现
      • 2、JS-SDK
    • 九、vue 项目部署在公众号上使用

一、微信公众号简介

1、微信公众号是什么?
微信公众号平台是给个人、企业和组织提供业务服务与用户管理能力的全新服务平台;
2、微信公众号分类

订阅号:针对媒体和个人提供新的信息传播方式,主要是在微信里给用户传达资讯(杂志、新闻、娱乐等),适用于个人和媒体,一天可群发消息一次;
服务号:为企业和组织提供更加强大的业务服务与用户管理能力偏向于服务类交互(银行),适用于企业、组织、政府,一个月可群发消息4次;
小程序:一种新的开放能力,开发者可以快速开发一个小程序,小程序可以在微信内便捷的获取和传播;
企业微信:继承企业号所有能力,同时为企业提供专业的通讯工具,丰富的办公应用与 api,助力企业高效沟通与办公;

3、订阅号和服务号区别

  • 推送频率:订阅号一天一次,服务号一个月4次;
  • 适用群体:订阅号侧重与媒体、个人,服务号侧重企业、组织、政府;
  • 提供功能:订阅号包含大部分功能,认证的服务号包含全部功能;

二、注册/登录微信公众号

1、注册网址
官网:https://mp.weixin.qq.com/
2、注册流程(注册直接根据提示填写相应信息就可以了)

打开官网,点击右上角“立即注册”
选择订阅号注册(服务号需要公司注册信息,这里注册订阅号)
依次输入信息点击注册(邮箱需要未注册过微信相关东西的账号)

3、注册完成之后回到首页,直接输入账号密码登录就可以了,也可以扫码登录;

4、登录成功之后可以在左侧带单 基本功能 找到自己的 AppID 和 AppSecret ,这两个参数在后面开发的时候会用到;

三、功能介绍

1、编辑模式(个人开发者,无需服务器)

微信公众号开发_第1张图片

草稿箱:查看草稿、新建图文等消息;
素材库:提前上传图片、音频、视频,方便写文章的时候直接使用;
发表记录:对已发布的文章进行管理,可编辑删除;
原创:设置可转载账号;
消息:消息管理中心;
赞赏:文章赞赏回复设置以及数据的分析;
用户管理:管理已关注、黑名单;
视频弹幕:对视频弹幕进行设置;
自动回复:对关键词回复、收到消息回复、被关在回复信息进行设置;
自定义菜单:设置公众号底部的菜单;
话题标签:针对话题、页面模板设置;
投票:可以新建和管理投票;
号内搜索:设置公众号搜索词后,帮助用户更快捷检索号内关联内容

上面这一部分的功能可以让开发者直接在页面中配置我们的公众号,而不需要任何的代码开发,这种模式只能配置:自动回复、自定义菜单、话题标签、投票、号内搜索等比较通用的功能;如果你的项目里有需要引入第三方页面或者一些通用之外的定制化功能则需要通过开发模式来实现;

2、开发模式

微信公众号开发_第2张图片

基本配置:公众号基本信息查看,服务器配置;
开发者工具:开发这工具(开发者文档、在线调试工具、we开发工具、公众平台测试账号等)入口;
运维中心:数据监控、日志查询、接口报警等信息;
接口权限:查看当前用账户接口权限,接口代表的就是页面功能;

开发模式需要配置服务器,服务器一旦开启配置之后,编辑模式的相关配置将会失效;

四、实战开发

开发之前请先打开开发者工具,仔细阅读开发者文档;

开发模式整体流程图:
微信公众号开发_第3张图片

1、配置服务器

开发者文档中打开“接口测试号申请” => “进入微信公众帐号测试号申请系统”,这里需要填写接口配置信息和JS接口安全域名;
1.1、创建服务 express
这里是简单的构建一个express 服务,也可以使用 express 提供的项目生成器来构建;

1、新建文件夹 wechat_test
2、控制台执行 npm init,创建一个 package.json 文件
3、安装 express :npm i express
4、在 package.json 同级新建文件 app.js
5、控制台运行 app.js 服务,node app.js

//引入express模块
const express = require('express');
//创建app对象
const app = express();
//监听端口号
app.listen(3000,()=>{
	console.log('服务器运行成功了')
})

运行成功,控制台会输出:服务器运行成功了;

1.2、配置测试号-接口配置信息
url:微信服务器访问不到局域网的网址,这里需要对我们的服务器域名做一下映射,将本地域名映射为外网网址;我们可以借助 花生壳 - 内网穿透 来实现;
token:是参与服务器返回参数 signature 加密的,这里面可以随意填写,越复杂越好;signature 下面会说到用途;

配置成功之后控制台会输出如下参数:

{
  signature: '51631893d3f7711b6bf547090f65389a41a6c4b0', // 微信加密签名
  echostr: '3846949982007385053', //微信随机字符串
  timestamp: '1647073868', // 微信发送请求时间戳
  nonce: '1150241684' // 微信随机数字
}

1.3、验证服务器的有效性

将 [token,nonce,timestamp] 按照字典排序,然后转字符串进行sha1加密;
得到数据和微信传递过来的 signature 进行对比,相等说明消息是来自于微信服务器,否则就不是;

需要安装sha1:npm i sha1

//引入express模块
const express = require('express');
//引入sha1加密工具
const sha1 = require('sha1')
//创建app对象
const app = express();
const config = {
	token:'xxxx'
}
//中间件,判断服务器的有效性
app.use((req,res,next) =>{
	const { signature, echostr, timestamp, nonce } = req.query;
	const { token } = config;
	const sha1Str = sha1([timestamp,nonce,token].sort().join(''));//sha1需要手动安装引入
	if(sha1Str === signature){
		res.send(echostr);
	}else{
		res.send('error');
	}
})
//监听端口号
app.listen(3000,()=>{
	console.log('服务器运行成功了')
})

token 配置在 config 文件中,和上一步设置的 token 相同;

2、模块化

模块复用,针对上面的代码进行模块化拆分,首先文件改造
微信公众号开发_第4张图片
将 config 配置和中间件函数提出出来
1、app.js

//引入express模块
const express = require('express');
//引入auth中间件函数
const auth = require('./wechat/auth');
//创建app对象
const app = express();
//中间件函数
app.use(auth());
//监听端口号
app.listen(3000,()=>{
	console.log('服务器运行成功了')
})

2、config.js

module.exports={
	token: "xxs520!!",
	appID: "wx5e6b8daad9eba98f",
	appsecret: "8bf76bbeeddf977ef5b3a73cca0b831b"
}

3、auth.js

//引入配置对象
const config = require('config');
//引入sha1加密工具
const sha1 = require('sha1')
module.exports = () =>{
	return (req,res,next) =>{
		const { signature, echostr, timestamp, nonce } = req.query;
		const { token } = config;
		const sha1Str = sha1([timestamp,nonce,token].sort().join(''));//sha1需要手动安装引入
		if(sha1Str === signature){
			res.send(echostr);
		}else{
			res.send('error');
		}
	}
}

模块化更多的是一种思想,目的是为例复用项目里面的功能或者方法;

五、获取 access_token

开发者文档中-开始开发里有个获取 access_token 的功能,这里面有对 access_token 的介绍,可以先去了解一下;

1、access_token 是什么?

access_token 是微信公众号的全局唯一的接口调用凭据,公众号的所有接口都需要使用 access_token ;
特点:

access_token 的有效期是 2 个小时,过期之后需要重新获取(提前5分钟请求);
重复获取将会导致上一次的 access_token 失效;
日调用量 2000次;

2、获取 access_token 功能实现

1、设计思路

初次调用:发送请求获取 access_token ,然后保存在本地;
再次调用:去本地读取文件,判断是否过期;过期了重新获取并更新本地保存的 access_token ,没过期则跳过;

整理:获取 access_token 时判断本地是否有access_token ,没有则获取并保存在本地;有则判断是否过去;

2、代码实现
安装 request、request-promise-native:npm i request,npm i request-promise-native

//引入require-promise-native,返回值是一个promise 对象
const rp = require('request-promise-native');
//引入fs,读写文件
const { writeFile, readFile } = require('fs');
//引入配置对象
const { appID, appsecret } = require('../config');
//定义类,获取access_token
class Wechat {
	constructor(){}
	//获取access_token
	getAccessToken(){
		//定义请求地址
		const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appID}&secret=${appsecret}`;
		//返回一个promise,保证接口所有的状态都能正常返回
		return new Promise((resolve, reject)=>{
			//使用request、request-promise-native 
			//发送请求
			rp({method:'GET', url, json:true}).then(res=>{
				//重写过期时间
				res.expires_in = Date.now() + (res.expires_in -300)*1000;
				resolve(res);
			}).catch(err=>{
				reject('getAccessToken:'+ err);
			})
		})
	}
	//保存access_token,将入参保存为文件
	saveAccessToken(accessToken){
		accessToken = JSON.stringify(accessToken);
		return new Promise((resolve, reject)=>{
			//写入的文件,希写入的内容
			writeFile('./accessToken.txt', accessToken, err=>{
				if(!err){
					resolve();
				}else{
					reject('saveAccessToken:'+err);
				}
			});
		})	
	}
	//读取access_token
	readAccessToken(){
		return new Promise((resolve, reject)=>{
			//写入的文件,希写入的内容
			readFile('./accessToken.txt', (err, data)=>{
				if(!err){
					data = JSON.parse(data);
					resolve(data);
				}else{
					reject('readAccessToken:'+err);
				}
			});
		})	
	}
	//判断access_token是否有效
	isVaildAccessToken(data){
		if(!data && !data.access_token && !data.expires_in){
			return false;
		}
		return data.expires_in > Date.now();
	}
	//获取access_token
	fetchAccessToken(){
		return new Promise((resolve, reject)=>{
			this.readAccessToken().then(async res=>{
				//判断是否存在,存在直接读取,不存在则重新请求并保存然后暴露出来
				if(this.isVaildAccessToken(res)){
					resolve(res);
				}else{
					const res = await this.getAccessToken();
					await this.saveAccessToken(res);
					resolve(res);
				}
			}).catch(async err=>{
				const res = await this.getAccessToken();
				await this.saveAccessToken(res);
				resolve(res);
			})
		})
	}
}
//模拟测试
const wx = new Wechat();
wx.fetchAccessToken();

然后在控制台执行这个 js 文件;

六、自动回复功能

1、准备工作

关注自己的测试号:在测试号管理里面扫描 “测试号二维码” 来关注自己的测试号;
然后在测试号发送消息,消息会由微信公众号平台转发到自己的服务器上;

微信服务器会发送两种请求的数据给开发者服务器:
1.1、GET:验证服务器的有效性;
1.2、POST:微信服务器会将用户的消息以 POST 的方式发送给开发者服务器;
1.3、微信服务器发送 POST 的消息是 XML 类型的数据,我们需要进一步操作:将数据接收、xml转译成 js 对象,格式化;
1.4、如果开发者服务器没有回复消息给微信服务器,微信服务器回发送3次消息,所以我们需要在接收到消息之后进行回复;

2、代码实现

2.1、直接在 auth.js 文件中修改,改造服务器的有效性方法;

//引入配置对象
const config = require('../config');
const { getUserData, parseXml, formatMsg } = require('../utils/tool');
const msgTemp = require('./msgTemp');
const replay = require('./replay');
//引入sha1加密工具
const sha1 = require('sha1')
module.exports = () =>{
	return async (req,res,next) =>{
		const { signature, echostr, timestamp, nonce } = req.query;
		const { token } = config;
		const sha1Str = sha1([timestamp,nonce,token].sort().join(''));//sha1需要手动安装引入
		if(req.method == 'GET'){
			//当前是验证服务器有效性消息
			if(sha1Str === signature){
				res.send(echostr);
			}else{
				res.end('error');
			}
		} else if(req.method == 'POST'){
			if(sha1Str !== signature){
				res.end('error');
			}
			//接收请求体中数据(用户在客户端发送的消息)
			let xmlData = await getUserData(req);
			//将xml解析成js对象
			let jsData = await parseXml(xmlData);
			//格式化数据
			let msg = formatMsg(jsData);
			//实现自动回复
			let options = replay(msg);
			let replayMsg = msgTemp(options);
			//发送数据给微信服务器
			res.send(replayMsg);
		} else {
			res.end('error');
		}
	}
}

2.2、utils/tool.js:接收到微信服务器后对数据处理的一些常规方法;
安装 xml2js:npm i xml2js

const { parseString } = require('xml2js');
module.exports = {
	//获取用户发送的消息
	getUserData(req){
		return new Promise((resolve, reject)=>{
			let xmlData = '';
			//当流式数据传递过来时会触发该事件
			req.on('data', ()=>{
				//读取的数据是buffer,需要转换成字符串
				xmlData += data.tostring();
			})
			//数据传递结束时触发,将最终数据返回
			.on('end', ()=>{
				resolve(xmlData);
			})
		})
	},
	//解析xml为js,借助插件
	parseXml(data){
		return new Promis((resolve, reject)=>{
			parseString(data, {trim:true}, (err,data)=>{
				if(!err){
					resolve(data);
				}else{
					reject(err);
				}
			})
		})
	},
	//格式化,去除无用数据,去除空数据,数组转化为key-value
	formatMsg(msg){
		let message = {};
		msg = msg.xml;
		if(typeof msg === 'object'){
			for(let i in msg){
				let value = msg[i];
				if(Array.isArray(value) && value.length != 0){
					message[i] = value[0]; 
				}
			}
		}
		return message;
	}
}

2.3、replay.js:对所有收到的消息、事件进行统一处理,这里只是写了一部分;

//处理接收到的消息
//处理接收普通消息、接收事件推送
module.exports = (msg) => {
	//接收人和发送人需要互换角色
	let options = {
		ToUserName:msg.FromUserName,
		FromUserName:msg.ToUserName,
		CreateTime:Date.now(),
		MsgType:msg.MsgType
	}
	let content = '初始消息';
	//普通消息
	if(msg.MsgType == 'text'){
		if(msg.Content == '1'){//全匹配
			content = `测试使用数据1`;
		}else if(msg.Content.match('2')){//半匹配
			content = `测试使用数据2`;
		}
	}else if(msg.MsgType == 'image' || msg.MsgType == 'voice'){
		options.MediaId = msg.MediaId;
	}else if(msg.MsgType == 'video'){
		...
	}else if(msg.MsgType == 'shortvideo'){
		...
	}else if(msg.MsgType == 'location'){
		...
	}
	//事件推送
	....
	options.content = content;
	return options;
}

2.4、msgTemp.js:用户服务器回复微信服务器消息的模板封装;

//回复消息的模板
module.exports = options =>{
	//消息模板在官网上获取,由于上一步发送和接收人已经替换,这里不需要再次替换
	let str = `<xml>
    <ToUserName><![CDATA[${options.ToUserName}]]></ToUserName>
    <FromUserName><![CDATA[${options.FromUserName}]]></FromUserName>
    <CreateTime>${options.CreateTime}</CreateTime>
    <MsgType><![CDATA[${options.MsgType}]]></MsgType>`;
	if(options.MsgType == 'text'){
		str += `<Content><![CDATA[${options.content}]]></Content>`;
	}else if(options.MsgType == 'image'){
		str += `<Image><MediaId><![CDATA[${options.MediaId}]]></MediaId></Image>`;
	}else if(options.MsgType == 'voice'){
		str += `<Voice><MediaId><![CDATA[${options.MediaId}]]></MediaId></Voice>`;
	}else if(options.MsgType == 'video'){
		str += `<Video>
				    <MediaId><![CDATA[${options.MediaId}]]></MediaId>
				    <Title><![CDATA[${options.title}]]></Title>
				    <Description><![CDATA[${options.description}]]></Description>
				  </Video>`;
	}else if(options.MsgType == 'music'){
		str += `<Music>
				    <Title><![CDATA[${options.title}]]></Title>
				    <Description><![CDATA[${options.description}]]></Description>
				    <MusicUrl><![CDATA[${options.musicUrl}]]></MusicUrl>
				    <HQMusicUrl><![CDATA[${options.hqMusicUrl}]]></HQMusicUrl>
				    <ThumbMediaId><![CDATA[${options.MediaId}]]></ThumbMediaId>
				  </Music>`;
	}else if(options.MsgType == 'news'){
		str += `<ArticleCount>${options.content.length+1}</ArticleCount><Articles>`
		options.content.forEach(item=>{
			str += `<item>
				      <Title><![CDATA[${item.title}]]></Title>
				      <Description><![CDATA[${item.description}]]></Description>
				      <PicUrl><![CDATA[${item.picUrl}]]></PicUrl>
				      <Url><![CDATA[${item.url}]]></Url>
				    </item>`
		})
    
    str += `</Articles>`;
	}
	str += '';
	return str;
}

这里对接收到的普通消息、事件推送进行统一的处理,对回复消息时的模板也进行了封装;最终可以关注自己的测试号,然后手机上发送消息,然后在控制台查看输出信息;

七、自定义菜单

请熟读自定义菜单的文档:https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html;
注意:

1、自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。
2、一级菜单最多4个汉字,二级菜单最多8个汉字,多出来的部分将会以“…”代替。
3、菜单必须先删除才能再次创建,不能直接覆盖;

在 accress_token 模块新增两个方法:新增菜单、删除菜单;也就是为 Wechat 类新增两个方法:

//自定义菜单
createMenu(menu){
	return new Promise(async (resolve, reject) => {
		try{
			//获取access_token
			let data = await this.fetchAccessToken();
			let url = `https://api.weixin.qq.com/cgi-bin/menu/create?access_token=${data.access_token}`;
			//发送请求
			const res = await rp({method:'POST', url, json:true, body:menu});
			resolve(res);
		}catch(e){
			console.log(e);
		}
	})
}
//删除菜单
deleteMenu(){
	return new Promise(async (resolve, reject) => {
		try{
			//获取access_token
			let data = await this.fetchAccessToken();
			let url = `https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=${data.access_token}`;
			let res = await rp({method:'GET', url, json:true});
			resolve(res);
		}catch(e){
			console.log(e);
		}
	})
}

先执行删除,在执行新增:

(async ()=>{
	//模拟测试
	const wx = new Wechat();
	await wx.deleteMenu();
	await wx.createMenu(menu);
})()

菜单配置:

module.exports = {
     "button":[
     	{	
          "type":"click",
          "name":"今日歌曲",
          "key":"V1001_TODAY_MUSIC" //随意设置,在点击事件中会在eventKey获取到
      	},
      	{
           "name":"菜单",
           "sub_button":[
           {	
               "type":"view",
               "name":"搜索",
               "url":"http://www.soso.com/" //跳转的网址
            },
            {
               "type":"click",
               "name":"赞一下我们",
               "key":"V1001_GOOD"
            }]
        }
    ]
}

可以参考官网上的类型来设置菜单的数据;

八、微信中的网页开发

1、简单实现

借助 ejs 模板引擎来实现在微信中网页的开发,安装 ejs 插件:npm i ejs,在 app.js 同级新建 views 文件夹,然后在文件夹里新建 link.ejs 文件;在app.js 里面使用路由:

//引入express模块
const express = require('express');
//引入auth中间件函数
const auth = require('./wechat/auth');
//创建app对象
const app = express();
//配置模板引擎目录
app.set('views','./views');
//配置模板引擎,可以将数据和模板合并然后生成 HTML 文本
app.set('view engine','ejs');
//页面路由
app.get('/link',(req,res)=>{
	//渲染页面,将渲染好的页面返回给用户
	res.render('link');
})
//中间件函数
app.use(auth());
//监听端口号
app.listen(3000,()=>{
	console.log('服务器运行成功了')
})

link.ejs :跟 html 一样

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>test</title>
	</head>
	<body>
		<div>sasasasas</div>
	</body>
</html>

然后运行 app.js ,就可以在浏览器打开 localhost:3000/link 查看 link 页面的内容了;

2、JS-SDK

微信JS-SDK是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包;通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验;

2.1、获取 ticket
jsapi_ticket 是公众号用于调用微信 JS 接口的临时票据。正常情况下,jsapi_ticket 的有效期为7200秒,通过 access_token 来获取。由于获取 jsapi_ticket 的 api 调用次数非常有限,频繁刷新 jsapi_ticket 会导致 api 调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket ;

获取 ticket 跟获取 access_token 的方法基本一致,我将代码放到获取 access_token 文件中:

//将文件固定在一个位置创建,防止不同位置调用方法文件创建位置变动
var path = require('path');
//获取ticket
	getTicket(){
		return new Promise(async (resolve, reject)=>{
			//获取access_token
		let data = await this.fetchAccessToken();
		//定义请求地址
		const url = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${data.access_token}&type=jsapi`;
		//返回一个promise,保证接口所有的状态都能正常返回
			//使用request、request-promise-native 
			//发送请求
			rp({method:'GET', url, json:true})
			.then(res=>{
				//重写过期时间
				resolve({
					ticket:res.ticket,
					expires_in:Date.now() + (res.expires_in -300)*1000
				});
			})
			.catch(err=>{
				reject('getTicket:'+ err);
			})
		})
	}
	//保存ticket,将入参保存为文件
	saveTicket(ticket){
		ticket = JSON.stringify(ticket);
		let file = "./ticket.txt";
		let fileName = path.resolve(__dirname,file );
		return new Promise((resolve, reject)=>{
			//写入的文件,希写入的内容
			writeFile(fileName , ticket, err=>{
				if(!err){
					resolve();
				}else{
					reject('saveTicket:'+err);
				}
			});
		})	
	}
	//读取ticket
	readTicket(){
		let file = "./ticket.txt";
		let fileName = path.resolve(__dirname,file );
		return new Promise((resolve, reject)=>{
			//写入的文件,希写入的内容
			readFile(fileName , (err, data)=>{
				if(!err){
					data = JSON.parse(data);
					resolve(data);
				}else{
					reject('readTicket:'+err);
				}
			});
		})	
	}
	//判断ticket是否有效
	isVaildTicket(data){
		if(!data && !data.ticket && !data.expires_in){
			return false;
		}
		return data.expires_in > Date.now();
	}
	//获取ticket
	fetchTicket(){
		return new Promise((resolve, reject)=>{
			this.readTicket().then(async res=>{
				//判断是否存在,存在直接读取,不存在则重新请求并保存然后暴露出来
				if(this.isVaildTicket(res)){
					resolve(res);
				}else{
					const res = await this.getTicket();
					await this.saveTicket(res);
					resolve(res);
				}
			}).catch(async err=>{
				const res = await this.getTicket();
				await this.saveTicket(res);
				resolve(res);
			})
		})
	}

有些方法跟获取 access_token 的方法基本一样,这里可以将方法改造一下,统一调用;

2.2、验证 JS-SDK
规则:
1、组合参与签名的四个参数:jsapi-tacket临时票据、noncestr随机字符串、timestamp时间戳、url当前服务器地址;
2、排序、以&拼接,sha1加密;

let arr = [
	`jsapi-tacket=${tacket}`,
	`noncestr=${noncestr}`,
	`timestamp=${timestamp}`,
	`url=${uel}/link` //拼接上当前页面的路径
]
let sha1Str = sha1(arr.sort().join('&'));

2.3、使用 JS-SDK(参考官网)
1、登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”,也就是用户服务器的域名(不带协议名);
2、引入 js 文件:http://res.wx.qq.com/open/js/jweixin-1.6.0.js,引入之后就有一个 wx 对象可以全局使用;
3、通过 config 接口注入权限验证配置;
4、通过 ready 接口处理成功验证;
5、通过 error 接口处理失败验证;
6、在页面上使用:

//配置tacket
//页面路由
app.get('/link',(req,res)=>{
    //生成js-sdk
    	//组合参与签名的四个参数:jsapi-tacket临时票据、noncestr随机字符串、timestamp时间戳、url当前服务器地址
    	//排序、以&拼接,sha1加密
    let arr = [
    	`jsapi-tacket=${tacket}`,
    	`noncestr=${noncestr}`,
    	`timestamp=${timestamp}`,
    	`url=${uel}/link` //拼接上当前页面的路径
    ]
    let sha1Str = sha1(arr.sort().join('&'))//渲染页面,将渲染好的页面返回给用户
	res.render('link');
})

link.ejs

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>test</title>
	</head>
	<body>
		<div id="link">语音识别</div>
		<div class="content"></div>
		<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
		//引入zepto 方便操作元素
		<script type="text/javascript" src="http://cdn.bootcss.com/zepto/1.0rc1/zepto.min.js"></script>
		<script type="text/javascript">
			wx.config({
			  debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
			  appId: 'wx5e6b8daad9eba98f', // 必填,公众号的唯一标识
			  timestamp: <%= timestamp %>, // 必填,生成签名的时间戳
			  nonceStr: <%= noncestr %>, // 必填,生成签名的随机串
			  signature: <%= signature %>,// 必填,签名
			  jsApiList: ['startRecord', 'stopRecord', 'translateVoice'] // 必填,需要使用的JS接口列表
			});
			//js-sdk相关功能接口一般在这这里使用
			wx.ready(function(){
				// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,
				//所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。
				//对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
				
				//验证接口是否有权限,测试阶段使用
				wx.checkJsApi({
				  jsApiList: ['chooseImage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
				  success: function(res) {
				  // 以键值对的形式返回,可用的api值true,不可用为false
				  // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
				  }
				});
				//语音识别
				let isLink = false;
				//点击操作
				$('#link').tap(function(){
					if(!isLink){
						//开始录音
						wx.startRecord();
						isLink = true;
					}else{
						wx.stopRecord({
						  success: function (res) {
						  	//结束录音后会自动上传到微信服务器,并返回一个对应id
						    var localId = res.localId;
						    isLink = false;
						    //转化为文字
						    wx.translateVoice({
							  localId: localId, // 需要识别的音频的本地Id,由录音相关接口获得
							  isShowProgressTips: 1, // 默认为1,显示进度提示
							  success: function (res) {
							    $('.content').html(res.translateResult)
							  }
							});
						  }
						});
					}
				})
			});
			wx.error(function(res){
				// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,
				//也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
			});
		</script>
	</body>
</html>

九、vue 项目部署在公众号上使用

1、在vue项目 index.html 文件中引入 http://res.wx.qq.com/open/js/jweixin-1.6.0.js,引入之后就可以全局使用 wx 对象;
2、配置 wx.config ,这里是使用 JS-SDK 的一下基础配置项,在项目初始化的时候调用一次;
3、然后在wx.ready 里面处理 JS-SDK 提供的一些调用接口;
4、代码打包,发布到线上,由公众号服务端调用对应的页面就可以了;

以上就是微信公众号开发的内容了,根据视频学习;这里只是借助视频资料大致的了解和实现部分功能;

你可能感兴趣的:(前端,微信公众号,编辑模式,开发模式)