用Nodejs来自定义微信菜单

    以前用php自定义过菜单。当时直接利用curlpost数据就行了。今天用nodejs重新写了下。发现nodejs的坑略多还是。下面是两种方法,第二种用了下promise。其实没有太大区别。

    中间遇到了一些问题,我把它们写到csdn上面了。小伙伴们自己看看:csdn问题。中间一定要注意的一个问题是我们通过微信API来get到的菜单和我们create需要的菜单是完全不一样的,比如说没有menu。这会导致创建菜单失败。因为微信对于消息的语法非常严格。

    下面直接就上代码了,我们这里就只用了http的原生方法getrequest发送请求。下面的menu.json是一个的按钮json文件。注意去微信官方api上看限制条件。config里面配置了我的token,appid,secrete等等。


    第一种方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    const https = require('https'),
    config = require('./config.json'),
    querystring = require('querystring');
    var menus = require('./menu.json'),
    strMenus = JSON.stringify(menus),
    optionAccess = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+config.appid+"&secret="+config.appSecret,
    access_token;
    https.get(optionAccess,function(res){
    var body = "";
    res.on('data',function(d){
    body += d;
    })
    res.on('end',function(){
    var parsed = JSON.parse(body);
    createMenu(parsed.access_token);
    })
    }).on('error',(e)=>{
    console.log(e.message);
    })
    function createMenu(access_token){
    var data = "";
    var options = {
    protocol:'https:',
    host:'api.weixin.qq.com',
    port:443,
    path:'/cgi-bin/menu/create?access_token='+access_token,
    method:'POST',
    headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(strMenus)
    }
    }
    var req = https.request(options,(res)=>{
    res.on('data',(chunk)=>{
    data+=chunk;
    })
    res.on('end',()=>{
    var message = JSON.parse(data);
    if(message.errmsg){
    console.log("返回信息:"+message.errmsg+'; 返回码:'+message.errcode);
    }
    })
    })
    req.on('error',(e)=>{
    console.log(e);
    })
    req.write(new Buffer(strMenus));
    req.end();
    }

    第二种方法

    细心的小伙伴会发现其实我没有改动什么代码。这里promise的作用体现的不明显。当有很多的次序请求的时候用promise会很好。以前我总是想,我可以直接在调用promise的地方放一个函数,然后在内部调用这个外部调用的函数。这其实就是callback。如果有很多层调用的时候,就会很乱。现在我能知道promise的好了。下面还用到了es6的一些小特性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    const https = require('https'),
    config = require('./config.json');
    var menus = require('./menu.json'),
    strMenus = JSON.stringify(menus);
    /**
    * [getAccessToken 获取access_token值]
    * return promise对象
    */
    function getAccessToken(){
    var access_token = "",
    optionAccess = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+config.appid+"&secret="+config.appSecret;
    return new Promise(function(resolve,reject){
    var body = "";
    https.get(optionAccess,(res)=>{
    res.on('data',(chunk)=>{
    body += chunk;
    })
    res.on('end',()=>{
    resolve(JSON.parse(body).access_token);
    })
    }).on('error',(e)=>{
    console.log(e.message);
    reject(e);
    })
    })
    }
    /**
    * [执行createMenu,创建菜单]
    */
    getAccessToken().then((access_token)=>{
    var data = "";
    var options = {
    protocol:'https:',
    host:'api.weixin.qq.com',
    port:443,
    path:'/cgi-bin/menu/create?access_token='+access_token,
    method:'POST',
    headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(strMenus)
    }
    }
    var req = https.request(options,(res)=>{
    res.on('data',(chunk)=>{
    data+=chunk;
    })
    res.on('end',()=>{
    var message = JSON.parse(data);
    if(message.errmsg){
    console.log(`返回信息:${message.errmsg}; 返回码:${message.errcode}`);
    }
    })
    })
    req.on('error',(e)=>{
    console.log(e);
    })
    req.write(new Buffer(strMenus));
    req.end();
    })


    总结

    看起来代码简单,我中间真的花了不少时间。主要原因还是感觉自己的api不熟。每写一个方法还要去查官方文档,比如get和post方法,会跟以前用到的比如express和koa的请求api弄混淆。真是不开心。希望以后会越来越熟练。加油! :)