微信公众号_订阅号_access_token_创建菜单_菜单name+表情
用于接口调用的一个必要参数
有了 access_token 就能实现所有的接口
- 特点:
1. 有效期为 2 小时,所以 2 小时要更新一次,提前 5 分钟更新(确保后续正常使用)
2. 如果重复获取,会导致上一次失效(需要 appid 和 appsecret 来获取)
3. access_token 存储至少要保留 512 个字符空间
4. 接口调用有限制,普通 2000次/天,测试号200次/天
- 请求方式 https GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
正常情况下,微信会返回下述JSON数据包给公众号:
{"access_token":"ACCESS_TOKEN", "expires_in":7200}
全局返回码,参见
- 设计思路
1. 第一次发送请求,获取 access_token,保存在将来 2 小时内使用
2. 以后发送请求,读取上一次保存的 access_token,判断是否过期
过期了,重新发送请求获取 access_token
没有过期,直接使用
优化为 getValidAccessToken():
直接 redAccessToken() 读取 access_token,判断是否过期 isValidAccessToken()
读取成功:
没过期,直接用
过期,发送请求 requestAccessToken() 获取 access_token,saveAccessToken()
读取失败
发送请求 requestAccessToken() 获取 access_token,saveAccessToken()
class WeChat {
async requestAccessToken(){
// 定义请求地址和参数
const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${???}&secret=${???}`;
// 导入发送请求的库 request-promise-native
// request 无需导入
// npm install request request-promise-native 发送请求(服务器端不能用 ajax)
// 请求方式,请求地址,如果响应回来的数据是JSON,则自动转化为 js 对象
// {"access_token":"ACCESS_TOKEN", "expires_in":7200}
const access_token= await rp({method:'GET', url, json: true});
// 重写过期时间,提前 5 分钟刷新
accessToken
return accessToken;
} // 返回一个 Promise 对象,其中有 access_token 对象
saveAccessToken(accessToken){ // 为了不被修改,使用 fs 模块将 access_token 写入 txt 文件
// 写入文件时,无法写 数组、函数、对象 类型的数据 [object Object]
new Promise((resolve, reject)=>{
writeFile('./access_token.txt', JSON.stringify(accessToken), err=>{
if(err){
reject(err);
}else{
resolve('保存 access_token 成功');
}
});
});
}
readAccessToken(){
new Promise((resolve, reject)=>{
readFile('./access_token.txt', (err, data)=>{
if(err){
reject(err);
}else{
resolve('读取 access_token 成功');
}
});
});
}
isValidAccessToken({expires_in}){
return (expires_in > Date.now);
}
}
// 直接测试:
(async ()=>{
const w = new WeChat();
w.getAccessToken().then(async result=>{
if(w.isValidAccessToken(result)){
return result;
}else{
result = await w.getAccessToken();
await w.saveAccessToken();
return result;
};
}).catch(err=>{ // 第一次读取,会失败
result = await w.getAccessToken();
await w.saveAccessToken();
return result;
}).then(result=>{
console.log(result);
});
})();
接口编程(方法需要参数 access_token)
- 自定义菜单(创建菜单,可能不会马上生效,微信服务器需要时间更新)
自定义菜单最多包括 3 个一级菜单
每个一级菜单最多包含 5 个二级菜单
菜单有 10 中类型
凡是 POST 请求都有 请求体数据
只要没有 请求体 数据,就一定是 GET 请求
- 创建菜单(要先删除老菜单,才能创建新菜单)
const body = {
"button":[
{
"type":"click",
"name":"一级菜单微信表情",
"key":"click"
},
{
"name":"二级菜单",
"sub_button":[
{
"type":"view",
"name":"百度",
"url":"http://www.baidu.com/"
},
{
"type":"miniprogram",
"name":"wxa",
"url":"http://mp.weixin.qq.com",
"appid":"wx286b93c14bbf93aa",
"pagepath":"pages/lunar/index"
},
{
"type":"click",
"name":"赞一下我们",
"key":"V1001_GOOD"
}]
}]
"button":[
{
"type":"click",
"name":"一级菜单微信表情",
"key":"click"
},
{
"name":"二级菜单",
"sub_button":[
{
"type":"view",
"name":"百度",
"url":"http://www.baidu.com/"
},
{
"type":"miniprogram",
"name":"wxa",
"url":"http://mp.weixin.qq.com",
"appid":"wx286b93c14bbf93aa",
"pagepath":"pages/lunar/index"
},
{
"type":"click",
"name":"赞一下我们",
"key":"V1001_GOOD"
}]
}]
};
creaetMenu(body){
// 获取到 access_token
const {access_token} = await this.fetchAccessToken();
// 2. 定义请求体地址
const url = `https://api.weixin.qq.com/cgi-bin/menu/create?access_token=${access_token}`;
// 3. 发送请求
const result = await rp({method:'POST', url, json:true, body});
return result;
}
- 尝试: 事件推送_接口
- 尝试: 查询_接口
源代码:
index.js
const express = require('express');
const {interfaceInit} = require('./interfaceInit'); const app = express(); interfaceInit(); // 中控服务器 初始化 app.listen(
3000,
err=>console.log(err?err:'\n\n服务器已启动\n\t\tHunting Happy!')
);
interfaceInit/index.js
/****
* access_token 对象____中控服务器----公众号的全局唯一接口调用凭据
*
* {
* access_token: '17_Nq3M5HMdnX3Xwkbi48uPEaVZ4qnh_H5B8HOzBy-DnXqLz6s9h3ALAPd6sk11K0zclzu0Ap3cZciBVp2aml9EuJGmSZ-iGKe7gFOwVUEYGhOB70Il9GeCMWtppgpXcdMzm7YaqVE_W55L1bgfBEQcAHAGJV',
* expires_in: 7200
* }
****/
const promiseRequest = require('request-promise-native');
const {APPID, APPSECRET, accessToken} = require('../config');
const {writeFile, readFile} = require('fs'); const {menu, deleteMenu, createMenu} = require('./menu'); class WeChat{
getValidAccessToken(){
if(this.access_token && this.isValidAccessToken(this)){
return Promise.resolve({
access_token: this.access_token,
expires_in: this.expires_in
});
}else{
return this.readAccessToken().then(async objAccessToken=>{
if (this.isValidAccessToken(objAccessToken)){
return objAccessToken;
}else{
const newObjAccessToken = await this.requestAccessToken();
await this.saveAccessToken(newObjAccessToken);
return newObjAccessToken;
}
}).catch(async err=>{
const newObjAccessToken = await this.requestAccessToken();
await this.saveAccessToken(newObjAccessToken);
return newObjAccessToken;
}).then(objAccessToken=>{
// 更新 WeChat
this.access_token = objAccessToken.access_token;
this.expires_in = objAccessToken.expires_in; // 返回 Promise 的 access_token
return Promise.resolve(objAccessToken);
});
};
} readAccessToken(){ // 一、读取access_token的方法
return new Promise((resolve, reject)=>{
readFile('./access_token.txt', (err, buffer)=>{
if(err){
reject('Read ./access_token.txt' + err);
}else{
resolve(JSON.parse(buffer.toString()));
}
});
});
} isValidAccessToken({expires_in}){ // 二、判断 access_token 是可用的吗?
return expires_in > Date.now();
}; async requestAccessToken(){ // 三、发送请求 getAccessToken() 获取 access_token
// 1. access_token 请求 url
const url = `${accessToken}appid=${APPID}&secret=${APPSECRET}`; // 2. POST 请求 access_token 对象
const objAccessToken = await promiseRequest({
method: 'POST',
url,
json: true
}); // 重写过期时间,提前 5 分钟刷新
objAccessToken.expires_in = Date.now() - (7200 - 300)*1000;
return objAccessToken;
} saveAccessToken(objAccessToken){ // 四、保存 access_token 到文件
return new Promise((resolve, reject)=>{ // 异步执行文件写完
writeFile('./access_token.txt', JSON.stringify(objAccessToken), err=>{
if(err){
reject("Write Success.");
}else{
resolve('access_token 最新已保存');
};
});
});
}
} module.exports = {
async interfaceInit(){
const wechat = new WeChat(); console.log('---- 先删除菜单 ----');
const deleteRet = await deleteMenu(wechat);
console.log(deleteRet); console.log('---- 再创建菜单 ----');
const createRet = await createMenu(wechat, menu);
console.log(createRet);
}
};
interfaceInit/menu.js
const {menuDelete, menuCreate} = require('../config');
const promiseRequest = require('request-promise-native'); module.exports = {
async deleteMenu(wechat){
const {access_token} = await wechat.getValidAccessToken();
const url = `${menuDelete}access_token=${access_token}`;
return await promiseRequest({method: 'Get', url, json: true});
}, async createMenu(wechat, menu){
const {access_token} = await wechat.getValidAccessToken();
const url = `${menuCreate}access_token=${access_token}`;
return await promiseRequest({method: 'POST', url, json: true, body: menu});
}, menu: {
"button":[
{
"type":"click",
"name":"一级菜单☀",
"key":"click"
},
{
"name":"二级菜单⛄",
"sub_button":[
{
"type":"view",
"name":"百度微信公众号_订阅号_access_token_创建菜单_菜单name+表情的更多相关文章
- PHP语言开发微信公众平台(订阅号)之注册
1.百度搜索"微信公众平台" 2.选择微信公众平台官网并单击打开 3.进入官网页面,单击 "立即注册" 进入注册页面 4.进入注册页面,单击订阅号 5.进入订阅 ...
- PHP语言开发微信公众平台(订阅号)之注册(1)
1.百度搜索"微信公众平台" 2.选择微信公众平台官网并单击打开 3.进入官网页面,单击 "立即注册" 进入注册页面 4.进入注册页面,单击订阅号 5.进入订阅 ...
- PHP语言开发微信公众平台(订阅号)之开启开发者模式
(1)打开上一篇我们从花生壳官网获得的外网网址就会看到localhost根目录下的文件(这里不再赘述php环境的搭建).注:因为外网网址在能联网时,访问外网网址的任何人都能看到根目录下的所有文件,不仅 ...
- PHP语言开发微信公众平台(订阅号)之开启基本功能及获得可用的服务器地址(2)
1.开启群发功能(单击功能菜单里的"群发功能",并在右侧页面中点击"同意以上声明") 2.(1)在开启开发者模式之前需要完善个人资料(完成头像上传即可) (2) ...
- PHP语言开发微信公众平台(订阅号)之curl命令
在开发过程中,经常会遇到要求用curl命令调用接口的情况 那么,什么是curl,简单来说curl是一个利用url语法规定来传输文件和哦数据的工具,支持很多协议,如 http.ftp.telent 等, ...
- PHP语言开发微信公众平台(订阅号)之curl命令(补充)
在之前的一篇随笔中,博主在调用curl命令上传文件时会经常出现上传方法过时的情况.如下图所示: 所以,我们只需要把上传方法换成创建CURLFile 类即可.如下所示 $ch = curl_init() ...
- 微信小程序、应用号、订阅号、服务号、企业号小总结
微信小程序是现在微信推出的一个新的项目,但是很多人都不是很清楚微信小程序是怎么一回事,不明白到底怎样分别微信小程序和别的公众号.订阅号等的区别,那么让小编来给你介绍一下. 微信小程序目前是内侧阶段,是 ...
- 微信公众平台测试帐号的注册与使用(自己的服务器<---->微信后台<---->测式公众号)
打开注册的网址:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login 用手机微信扫描网页左边的二维码,然后在手机上确认即可: 至此 ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十七):个性化菜单接口说明
前不久微信上线了个性化菜单接口,Senparc.Weixin SDK也已经同步更新. 本次更新升级Senparc.Weixin.MP版本到v13.5.2,依赖Senparc.Weixin版本4.5.4 ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(九):自定义菜单接口说明
上一篇<Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明>介绍了如何通过通用接口获取AccessToken,有了AccessToken,我们就可以来操作 ...
随机推荐
- 第二节:如何正确使用WebApi和使用过程中的一些坑
一. 基本调用规则 1. 前提 WebApi的默认路由规则为:routeTemplate: "api/{controller}/{id}", 下面为我们统一将它改为 routeTe ...
- maven私库nexus2.11.4迁移升级到nexus3.12.0
nexus简介 nexus是一个强大的maven仓库管理器,它极大的简化了本地内部仓库的维护和外部仓库的访问. nexus是一套开箱即用的系统不需要数据库,它使用文件系统加Lucene来组织数据 .n ...
- CDH5.16.1启动报错:Invalid value set for db.setupType, the valid values are EMBEDDED or EXTERNAL
1 自己的配置文件已经添加了配置,但是还是报错,由于是自建数据库 com.cloudera.cmf.db.setupType=EXTERNAL 2,索性注释掉这个参数,启动就ok了
- Java的三大特性
一.封装性 含义:对外不可见,保护属性和方法不被外部多看见 实现:通过关键字private声明,用get.set方法为外部访问. 引用的传递: static关键字:修饰属性(全局属性):修饰方法(直接 ...
- A Boring Problem UVALive - 7676 (二项式定理+前缀和)
题目链接: I - A Boring Problem UVALive - 7676 题目大意:就是求给定的式子. 学习的网址:https://blog.csdn.net/weixin_37517391 ...
- 迅为iTOP-4418/6818开发板-驱动-IO初始化配置介绍和例程
对于所有的处理器,pad 一般可以分为两大类:IO(输入输出).Power(VDD 和GDD).类似摄像头 IO.以太网 IO.PWM 的 IO 等等,都可以统称为 IO.一个 IO,有可能能够被配置 ...
- Django 上下文处理器
Django 上下文处理器 模板要在上下文中渲染. 上下文是django.template.Context的实例.django.template.RequestContext是Django提供的一个子 ...
- 一些日期的计算方式 PHP
一些日期的计算 某个月内的所有天数: public function getMonthDay ($date) { $stattime = strtotime(date('Ym01',strtotime ...
- [Kubernetes]yaml文件详解
应前一段时间夸下的海口:[Kubernetes]如何使用yaml文件使得可以向外暴露服务,说过要写一篇关于yaml文件详解的文章出来的,今天来总结一下.yaml文件用在很多地方,但是这里以介绍在Kub ...
- Linux进程组调度机制分析【转】
转自:http://oenhan.com/task-group-sched 又碰到一个神奇的进程调度问题,在系统重启过程中,发现系统挂住了,过了30s后才重新复位,真正系统复位的原因是硬件看门狗重启的 ...
- PHP语言开发微信公众平台(订阅号)之注册