微信公众号_订阅号_access_token_创建菜单_菜单name+表情

全局唯一接口调用凭据 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":"百度🌕",
                            "url":"http://www.atguigu.com/"
                        },
                        {
                            "type": "scancode_waitmsg",
                            "name": "扫码带提示🌸",
                            "key": "rselfmenu_0_0",
                        },
                        {
                            "type": "scancode_push",
                            "name": "扫码推事件",
                            "key": "rselfmenu_0_1",
                        },
                        {
                            "type": "pic_sysphoto",
                            "name": "系统拍照发图",
                            "key": "rselfmenu_1_0",
                            "sub_button": [ ]
                        },
                        {
                            "type": "pic_photo_or_album",
                            "name": "拍照或者相册发图",
                            "key": "rselfmenu_1_1",
                            "sub_button": [ ]
                        },
                    ]
                },
                {
                    "name":"二级菜单",
                    "sub_button":[
                        {
                            "type": "pic_weixin",
                            "name": "微信相册发图",
                            "key": "rselfmenu_1_2"
                        },
                        {
                            "name": "发送位置",
                            "type": "location_select",
                            "key": "rselfmenu_2_0"
                        },
                        // {
                        //   "type": "media_id",
                        //   "name": "图片",
                        //   "media_id": "MEDIA_ID1"
                        // },
                        // {
                        //   "type": "view_limited",
                        //   "name": "图文消息",
                        //   "media_id": "MEDIA_ID2"
                        // }
                    ]
                }
            ]
        }
    };

 config/index.js

  • const prefix = 'https://api.weixin.qq.com/cgi-bin/';
    module.exports = {
        token: 'FinnKou',
        APPID: 'wxba5329dbd7d2asd2cd32d',
        APPSECRET: '62ad75995d342f27668120fcb618d77b2e31',
        accessToken: `${prefix}token?grant_type=client_credential&`,
        menuDelete: `${prefix}menu/delete?`,
        menuCreate: `${prefix}menu/create?`
    };

 

posted @ 2018-12-26 15:44  耶梦加德  阅读(575)  评论(0编辑  收藏  举报