微信公衆號_訂閱號_源碼_用戶管理_自定義菜單_自動回覆用戶消息_素材上傳與下載

 一個公衆號,最多能夠建立 100 個標籤前端

查看手冊,根據 請求 url,以及參數說明,請求體格式,進行編程 。node

 

// 前端面試題
// 每當執行棧爲空時,就檢查微任務,有則進棧執行
// 當檢查無微任務了,再檢查宏任務,有則取一個宏任務進棧執行,執行完了,再檢查有沒有微任務......repeat面試

// 微任務:express

// 1. process.nextTick (nodejs)
// 2. Promise.then catch編程

 

// 宏任務:json

// 1. I/O (click事件、fs.writeFile)
// 2. setTimeout
// 3. setInterval
// 4. setImmediate (nodejs)
// 5. requestAnimationFrameapi

 

實例源代碼:promise

config/index.js
服務器

  • const prefix = 'https://api.weixin.qq.com/cgi-bin/'; module.exports = { SERVER_IP: 'localhost', SERVER_PORT: '3000', DB_PORT: '27017', token: 'FinnKou', APPID: 'wxba159db33d7d22c1d32d', APPSECRET: '62ad175995d2f246680fcb6218d77b24e31', prefix : prefix, ACCESSTOKEN: `${prefix}token?grant_type=client_credential&`, };

WeChat/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'); class WeChat{ getValidAccessToken(){ // 1. 判斷 wechat 對象裏的 access_token
            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(){ // 1、讀取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}){ // 2、判斷 access_token 是可用的嗎?
            return expires_in > Date.now(); }; async requestAccessToken(){ // 3、發送請求 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){ // 4、保存 access_token 到文件
            return new Promise((resolve, reject)=>{    // 異步執行文件寫完
                writeFile('./access_token.txt', JSON.stringify(objAccessToken), err=>{ if(err){ reject("Write Success."); }else{ resolve('access_token 最新已保存'); }; }); }); } }; const wechat = new WeChat(); module.exports = { wechat };

WeChat/fans.js

  • const {prefix} = require('../config'); const promiseRequest = require('request-promise-native'); const tagsCreate = `${prefix}tags/create?`;
    const tagsGet = `${prefix}tags/get?`;
    const tagsUpdate = `${prefix}tags/update?`;
    const tagsDelete = `${prefix}tags/delete?`;
     const usersGet = `${prefix}user/tag/get?`; const usersBatch = `${prefix}tags/members/batchtagging?`; const allUserGet = `${prefix}user/get?`;
     const userInfo = `${prefix}user/info?`;
     const sendall = `${prefix}message/mass/sendall?`; module.exports = { /**** 標籤操做 ****/
        // 增:根據 idName 建立一個標籤
     async createTag(wechat, idName){ const {access_token} = await wechat.getValidAccessToken(); const url = `${tagsCreate}access_token=${access_token}`; return await promiseRequest({method: 'POST', url, json: true, body:{"tag":{"name": idName}}}); }, // 查:根據 idNumber idName 獲取一個標籤
     async getTag(wechat){ const {access_token} = await wechat.getValidAccessToken(); const url = `${tagsGet}access_token=${access_token}`; return await promiseRequest({method: 'GET', url, json: true}); }, // 改:根據 idNumber newName 修改一個標籤
     async updateTag(wechat, idNumber, newName){ const {access_token} = await wechat.getValidAccessToken(); const url = `${tagsUpdate}access_token=${access_token}`; return await promiseRequest({method: 'POST', url, json: true, body:{"tag":{"id": idNumber, "name": newName}}}); }, // 刪:根據 idNumber 刪除一個標籤
     async deleteTag(wechat, idNumber){ const {access_token} = await wechat.getValidAccessToken(); const url = `${tagsDelete}access_token=${access_token}`; return await promiseRequest({method: 'POST', url, json: true, body:{"tag":{"id": idNumber}}}); }, /**** 根據標籤 操做用戶 ****/
        // 查:根據 idNumber 獲取用戶
        async getUsersByTag(wechat, idNumber, next_openid=''){ const {access_token} = await wechat.getValidAccessToken(); const url = `${usersGet}access_token=${access_token}`; return await promiseRequest({method: 'POST', url, json: true, body:{id:idNumber, next_openid}}); }, // 增:給一個標籤 idNumber 添加用戶 openid_list
     async addUsersToTag(wechat, idNumber, openid_list){ const {access_token} = await wechat.getValidAccessToken(); const url = `${usersBatch}access_token=${access_token}`; return await promiseRequest({method: 'POST', url, json: true, body:{id:idNumber, openid_list}}); }, /**** 獲取公衆號全部 用戶 ****/ async getAllUser(wechat, next_openid=''){ const {access_token} = await wechat.getValidAccessToken(); const url = `${allUserGet}access_token=${access_token}&next_openid=${next_openid}`; return await promiseRequest({method: 'GET', url, json: true}); }, /**** 根據 openid 操做用戶 ****/
        // 查:根據 openid 獲取用戶信息
     async getUserInfo(wechat, openid){ const {access_token} = await wechat.getValidAccessToken(); const url = `${userInfo}access_token=${access_token}&openid=${openid}`; return await promiseRequest({method: 'GET', url, json: true}); }, /**** 羣發消息給 標籤 下的粉絲 ****/ async sendToAllByTag(wechat, body){ const {access_token} = await wechat.getValidAccessToken(); const url = `${sendall}access_token=${access_token}`; return await promiseRequest({method: 'POST', url, json:true, body}); } };

WeChat/menu.js

  • const {prefix} = require('../config'); const promiseRequest = require('request-promise-native'); const menuDelete = `${prefix}menu/delete?`;
    const menuCreate = `${prefix}menu/create?`;
     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":[ { "name":"百度", "url":"http://www.baidu.com/", "type":"view" }, { "name": "掃碼帶提示🌸", "type": "scancode_waitmsg", "key": "rselfmenu_0_0" }, { "name": "掃碼推事件", "type": "scancode_push", "key": "rselfmenu_0_1" }, { "name": "系統拍照發圖", "type": "pic_sysphoto", "key": "rselfmenu_1_0", "sub_button": [ ] }, { "name": "拍照或者相冊發圖", "type": "pic_photo_or_album", "key": "rselfmenu_1_1", "sub_button": [ ] }, ] }, { "name":"一級菜單🌕", "sub_button":[ { "name": "微信相冊發圖", "type": "pic_weixin", "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"
                        // }
     ] } ] } };

WeChat/mediaSpace.js

  • /**** 圖片(image) 2M 支持PNG\JPEG\JPG\GIF格式 語音(voice) 2M 播放長度不超過60s,支持AMR\MP3格式 視頻(video) 10MB 支持MP4格式 ---- http GET 方式獲取 縮略圖(thumb) 64KB 支持JPG格式 ****/ const {prefix} = require('../config'); const promiseRequest = require('request-promise-native'); const request = require('request'); const {createReadStream, createWriteStream} = require('fs'); const mediaUpload = `${prefix}media/upload?`;
    const mediaGet = `${prefix}media/get?`;
     const materialNews = `${prefix}material/add_news?`;
    const materialNewsPic = `${prefix}media/uploadimg?`;
    const materialOthers = `${prefix}material/add_material?`;
     const materialGet = `${prefix}material/get_material?`;
     module.exports = { mediaSpace: { /*------------------------ 臨時素材 ------------------------*/
            // async upload(wechat, type, filePath){
            // const {access_token} = await wechat.getValidAccessToken();
            // const url = `${mediaUpload}access_token=${access_token}&type=${type}`;
            //         // // 以 form 表單方式 發送 post 請求上傳 文件流
            // return await promiseRequest({method: 'POST', url, json: true, formData:{"media": createReadStream(filePath)}});
            // },
            
            // async download(wechat, media_id, type, filePath){
            // const {access_token} = await wechat.getValidAccessToken();
            // let url = `${mediaGet}access_token=${access_token}&media_id=${media_id}`;
            //         // if(type === 'video'){
            // url.replace('https', 'http');
            // return await promiseRequest({method: 'GET', url, json:true});
            // }else{
            // await new Promise((resolve, reject)=>{
            // request(url) // 返回一個可讀流,使用管道寫入文件
            // .pipe(createWriteStream(filePath))
            // .once('close', err=>{
            // resolve(err);
            // });
            // });
            // };
            // },
            
        /*------------------------- 素材 ---------------------------*/ async upload(wechat, type, filePathOrNewsBody, isMeterialOrVideoBody = true){ const {access_token} = await wechat.getValidAccessToken(); let options = {method: 'POST', json: true}; if(isMeterialOrVideoBody === false){ options.url = `${mediaUpload}access_token=${access_token}&type=${type}`; // 以 form 表單方式 發送 post 請求上傳 文件流
                    options.formData = {media:createReadStream(filePathOrNewsBody)}; }else if(type === 'news'){ options.url = `${materialNews}access_token=${access_token}`; options.body = filePathOrNewsBody; }else if(type === 'newsImage'){ options.url = `${materialNewsPic}access_token=${access_token}`; options.formData = {media:createReadStream(filePathOrNewsBody)}; }else{ options.url = `${materialOthers}access_token=${access_token}&type=${type}`; console.log(options.url); options.formData = {media:createReadStream(filePathOrNewsBody)}; if(type === 'video'){ options.body = isMeterialOrVideoBody; }; }; return await promiseRequest(options); }, async download(wechat, media_id, type, filePath, isMeterial = true){ const {access_token} = await wechat.getValidAccessToken(); let url = `${materialGet}access_token=${access_token}`; if(isMeterial === false){ url = `${mediaGet}access_token=${access_token}&media_id=${media_id}`; if(type === 'video'){ url.replace('https', 'http'); return await promiseRequest({method: 'GET', url, json:true}); }else{ return await new Promise((resolve, reject)=>{ request(url) // 返回一個可讀流,使用管道寫入文件
     .pipe(createWriteStream(filePath)) .once('close', err=>{ resolve(err); }); }); } }else if(type === 'video' || type ===  'news'){ return await promiseRequest({method: 'POST', url, json: true, body: {media_id} }); }else{ await new Promise((resolve, reject)=>{ console.log(url); request({method: 'POST', url, json: true, body: {media_id}}) .pipe(createWriteStream(filePath)) // 返回一個可讀流, 使用管道寫入文件
                            .once('close', resolve); }); }; }, } };

app.js        

  • const express = require('express'); const {SERVER_PORT} = require('./config'); const handleRequest = require('./handleRequest'); const {wechat} = require('./WeChat'); const app = express(); // app.use(express.urlencoded({extended: true})); // app.use(handleRequest()); app.listen( SERVER_PORT, err=>console.log(err?err:'\n\n服務器已啓動\n\t\tHunting Happy!') ); /****************************** 自定義菜單 ***************************************/
    // const {menu, deleteMenu, createMenu} = require('./WeChat/menu'); // // (async ()=>{ // console.log('---- 先刪除菜單 ----'); // 若是有  // const deleteRet = await deleteMenu(wechat); // console.log(deleteRet); // // console.log('---- 再建立菜單 ----'); // const createRet = await createMenu(wechat, menu); // console.log(createRet); // })();
    
    /****************************** 標籤 與 用戶 *************************************/ const { createTag, getTag, updateTag, deleteTag, // 標籤的 增刪改查 getUsersByTag, addUsersToTag, // 使用 標籤 getAllUser, // 獲取全部用戶 getUserInfo, // 獲取用戶信息 sendToAllByTag // 標籤 羣發 } = require('./WeChat/fans'); (async ()=>{ let ret = await createTag(wechat, '0940_HTML5');    // 45157 重名
        console.log('建立一個標籤: '); console.log(ret); const {tags} = await getTag(wechat); console.log('獲取全部標籤對象: '); console.log(tags); /** * [ { id: 2, name: '星標組', count: 0 }, // 默認就有的 標籤 { id: 100, name: '0920_class', count: 0 }, { id: 101, name: 'beijing', count: 0 } ] * */
        if(tags[2]){ ret = await updateTag(wechat, tags[2].id, 'BeiPiao'); console.log('改標籤名字: '); console.log(ret); }; // ret = await deleteTag(wechat, tags[1].id);
        // console.log('刪除一個標籤: ');
        // console.log(ret);
     const {data: usersId, next_openid} = await getAllUser(wechat); console.log('獲取全部用戶: '); console.log(usersId); console.log(next_openid); ret = await getUserInfo(wechat, usersId.openid[0]); console.log('查詢 usersId[0] 的用戶信息: '); console.log(ret); // oSX3Z1aufrhsCwuEKXbVRfqOC1Wo 個人 openid
        ret = await sendToAllByTag({ filter:{ is_to_all: false, tag_id: 'oSX3Z1aufrhsCwuEKXbVRfqOC1Wo' }, text:{ content: '元旦快樂!' }, msgtype: 'text' }); })(); /****************************** 素材上傳下載 *************************************/
    // const {mediaSpace} = require('./WeChat/mediaSpace'); // const {resolve} = require('path'); // // (async ()=>{ // // console.log('---- 上傳臨時媒體素材 ----'); // // const moose = await mediaSpace.upload(wechat, 'image', resolve(__dirname, './1.jpg'), false); // // console.log(moose); // /* // { // type: 'image', // media_id: 'liuEDUcNu68MuWndCSopvv3Qr-d1qdgOKwkefKLVeRTZXdfhUVoC4q6I5viOStT_', // created_at: 1545979479 // } // */ // // console.log('---- 下載臨時媒體素材 ----'); // // await mediaSpace.download( // // wechat, // // 'liuEDUcNu68MuWndCSopvv3Qr-d1qdgOKwkefKLVeRTZXdfhUVoC4q6I5viOStT_', // // 'image', // // './2.jpg', // // false // // ); // /*-------------------------------------- 永久素材 ----------------------------------------------*/ // // console.log('---- 上傳永久媒體素材 ----'); // // const moose = await mediaSpace.upload(wechat, 'image', resolve(__dirname, './1.jpg')); // // console.log(moose); // /* // * { // media_id: 'bfzYrEwXqmeYiJIdBvbZ1E7Ox7UH8DfiSo66kKWZ4FM', // url: 'http://mmbiz.qpic.cn/mmbiz_jpg/8hj96GVnlibDVib3LJoyZSJFNpa7aIITL6nvCXrOszRiahQkPoZSQUS5Lpw8RiaibrAGia03JMkeKcibY9B6jcyuAcIhA/0?wx_fmt=jpeg' // } // * */ // console.log('---- 下載永久媒體素材 ----'); // await mediaSpace.download( // wechat, // 'bfzYrEwXqmeYiJIdBvbZ1JrCiKteRvzzqLK-_hZlBYg', // 'image', // './3.jpg', // ); // })(); // 前端面試題: // 每當執行棧爲空時,就檢查微任務,有則進棧執行 // 當檢查無微任務了,再檢查宏任務,有則取一個宏任務進棧執行,執行完了,再檢查有沒有微任務......repeat
        // 微任務:
            // 1. process.nextTick (nodejs)
            // 2. Promise.then catch
    
        // 宏任務:
            // 1. I/O (click事件、fs.writeFile)
            // 2. setTimeout
            // 3. setInterval
            // 4. setImmediate (nodejs)
            // 5. requestAnimationFrame /*********************************************************************************/
相關文章
相關標籤/搜索