全局唯一接口调用凭据 access_token

用于接口调用的一个必要参数

有了 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+表情的更多相关文章

    1. PHP语言开发微信公众平台(订阅号)之注册

      1.百度搜索"微信公众平台" 2.选择微信公众平台官网并单击打开 3.进入官网页面,单击 "立即注册" 进入注册页面 4.进入注册页面,单击订阅号 5.进入订阅 ...

    2. PHP语言开发微信公众平台(订阅号)之注册(1)

      1.百度搜索"微信公众平台" 2.选择微信公众平台官网并单击打开 3.进入官网页面,单击 "立即注册" 进入注册页面 4.进入注册页面,单击订阅号 5.进入订阅 ...

    3. PHP语言开发微信公众平台(订阅号)之开启开发者模式

      (1)打开上一篇我们从花生壳官网获得的外网网址就会看到localhost根目录下的文件(这里不再赘述php环境的搭建).注:因为外网网址在能联网时,访问外网网址的任何人都能看到根目录下的所有文件,不仅 ...

    4. PHP语言开发微信公众平台(订阅号)之开启基本功能及获得可用的服务器地址(2)

      1.开启群发功能(单击功能菜单里的"群发功能",并在右侧页面中点击"同意以上声明") 2.(1)在开启开发者模式之前需要完善个人资料(完成头像上传即可) (2) ...

    5. PHP语言开发微信公众平台(订阅号)之curl命令

      在开发过程中,经常会遇到要求用curl命令调用接口的情况 那么,什么是curl,简单来说curl是一个利用url语法规定来传输文件和哦数据的工具,支持很多协议,如 http.ftp.telent 等, ...

    6. PHP语言开发微信公众平台(订阅号)之curl命令(补充)

      在之前的一篇随笔中,博主在调用curl命令上传文件时会经常出现上传方法过时的情况.如下图所示: 所以,我们只需要把上传方法换成创建CURLFile 类即可.如下所示 $ch = curl_init() ...

    7. 微信小程序、应用号、订阅号、服务号、企业号小总结

      微信小程序是现在微信推出的一个新的项目,但是很多人都不是很清楚微信小程序是怎么一回事,不明白到底怎样分别微信小程序和别的公众号.订阅号等的区别,那么让小编来给你介绍一下. 微信小程序目前是内侧阶段,是 ...

    8. 微信公众平台测试帐号的注册与使用(自己的服务器<---->微信后台<---->测式公众号)

      打开注册的网址:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login 用手机微信扫描网页左边的二维码,然后在手机上确认即可: 至此 ...

    9. Senparc.Weixin.MP SDK 微信公众平台开发教程(十七):个性化菜单接口说明

      前不久微信上线了个性化菜单接口,Senparc.Weixin SDK也已经同步更新. 本次更新升级Senparc.Weixin.MP版本到v13.5.2,依赖Senparc.Weixin版本4.5.4 ...

    10. Senparc.Weixin.MP SDK 微信公众平台开发教程(九):自定义菜单接口说明

      上一篇<Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明>介绍了如何通过通用接口获取AccessToken,有了AccessToken,我们就可以来操作 ...

    随机推荐

    1. admin 后台操作表格

      1. app下创建 templates  运行的时候 先找全局的templates——> 按照app的注册顺序找templates中的文件 2. app下在创建一个urls.py include ...

    2. 后台挂载/卸载程序[Linux/Windows]

      后台挂载应用程序 即使关闭掉控制台窗口,该程序的进程也将会一直运行下去 #Windows 1.编写bat命令文件[形如:a.bat] 2.cmd执行:start /b a.bat #Linux noh ...

    3. es6编程建议和技巧点汇总

      大括号 特点:大括号(单独的大括号或者if等后的大括号)内是一个单独的作用域 注意点:在块级作用域内声明的函数,类似var,会被提升到大括号外,应避免在块级作用域内声明函数.如果确实需要,写成函数表达 ...

    4. 个人经验~ 利用5.7的sys库更好的排查问题

      一 简介:今天我们讲讲如何利用5.7的sys新库进行问题的排查二 描述   1 Sys库所有的数据源来自:performance_schema和information_schema.目标是把perfo ...

    5. javascript基础 之 代码规范

      1,变量名 1,变量名推荐使用小驼峰写法:类似于:firstName 2,全局变量和常量建议用大写:PI 3,支持下划线 2,缩进 1,一般使用4个空格当作缩进,tab建议少用 2,运算符左右和左花括 ...

    6. DDoS的类型及原理

      1.DDoS攻击: DDOS(Distributed Denial of Service),又称分布式拒绝服务攻击.骇客通过控制多个肉鸡或服务器组成的僵尸网络,对目标发送大量看似合法请求,从而占用大量 ...

    7. Node.js使用jszip实现打包zip压缩包

      一.前言 最近有这样的一个需求,需要把两个同名的.mtl文件和.obj文件打包成一个同名的.zip压缩包.刚开始文件不多的时候,只有几个,或者十几个,甚至二三十个的时候,还能勉强接受手动修改,但是随着 ...

    8. Pycharm工具导入requests包(python新手)

      在学习使用python的过程中选择了工具Pycharm,但是如下代码: ,起初导包一直报错,解决办法:File->Setting 点击右上角+号,打开搜素对话框 搜素需要的导包,并加入即可解决此 ...

    9. Django-DRF-图书增删改查 !!!

        自己封装的 class MyResponse(): def __init__(self): self.status = 100 self.msg = None @property def get_ ...

    10. python学习之Numpy.genfromtxt

      Python 并没有提供数组功能,虽然列表 (list) 可以完成基本的数组功能,但它并不是真正的数组,而且在数据量较大时,使用列表的速度就会慢的让人难受.Numpy 提供了真正的数组功能,以及对数据 ...