/ node

记,一次微信公众号开发

最近在做微信大作业,本着花了时间就尽量不划水的原则,就稍稍在此做个小记,我选的自定义,琢磨着开发个网易云音乐微信的低配版(期末了,时间限制,应该可以再深入)。

实现功能

说了是低配版,所以功能不多:

  • 搜索歌曲、歌手、专辑
  • 获取 TOP 榜
  • 随机听歌
  • 随机推荐
  • 下载 APP

开发语言

选择了 NodeJS

老实说老师教的是用 PHP 开发的,但是刚刚结束了个 PHP 大作业(精简版博客系统),看着个 PHP 也着实头大,所以了这就是我选择 NodeJS 作为开发语言的原因之一,至于之二吗,当然是对 Node 的喜爱了 ❤

用到的开源库

既然选择了 NodeJS, 自然少不了它背后强大的第三方开源模块

做到最后才觉得(这个模块还是存在一些问题的): 如果确实有必要使用第三方模块,建议尝试 wechat, 由于自己没有用过,也不好说是否好用,但 GitHub 上 star 数量还是能说明一些问题的

原生 - http 模块

作为一个 Node 初学者,还是希望在自我实践中接触更多原生特性,不能一味的使用第三方模块,基础不牢固就暂时不想整那些方便的

来自《深入浅出NodeJS》的一句忠告:

在 NPM 平台上,每个人都可以分享包到平台上,鉴于开发人员的水平不一,上面的包的质量也良莠不齐。

在这里自然不是造轮子,只是单纯的学习

  • http 我用到的自带模块

代码实例

netease.js:

// 相关参数设计参考 https://github.com/darknessomi/musicbox/wiki/网易云音乐API分析

const http = require('http');
const querystring = require('querystring');

/**
 * 搜索
 * @param {Object} search
 * @param {String} keywords
 * @param {String} type
 * @param {Function} cb
 */
function toSearch(keywords, type, cb) {
  const all_type = {
    song: 1,
    album: 10,
    artist: 100,
    playlist: 1000,
    userprofile: 1002
  };
  
  const postData = querystring.stringify({
    's': keywords,  // 搜索关键词
    'limit': 4,  // 返回结果的数量
    'type': all_type[type] || all_type.song,  // 搜索类型 [1 单曲, 10 专辑, 100 歌手, 1000 歌单 ,1002 用户 ]
    'offset': 0  // 偏移数量 用于分页
  });

  const options = {
    host: 'music.163.com',
    port: '80',
    method: 'POST',
    path: '/api/search/get',
    headers: {
      'User-Agent': 'hello/world',
      'Referer': 'http://music.163.com',
      'Cookie': 'appver=2.0.2',
      'Content-Type': 'application/x-www-form-urlencoded'
    }
  };

  const req = http.request(options, res => {
    let resData = '';
    
    // 解码
    res.setEncoding('utf8');

    // 接收数据 & 拼接
    res.on('data', (chunk) => {
      resData += chunk;
    });

    // 请求结束
    res.on('end', () => {
      cb(JSON.parse(resData).result);
    });
  });

  req.setTimeout(2000, () => {
    console.log('请求超时');
    req.abort();
    cb();
  });

  req.on('error', (e) => {
    console.log(`problem with request: ${e.message}`);
  });
  req.write(postData);
  req.end();
}

/**
 * 获取发现
 * @param {Function} 回调
 */
function getDiscover(cb) {
  const url = 'http://music.163.com/discover/';

  function find(str, cha, num){
    let x = str.indexOf(cha);

    for(let i = 0; i < num; i++){
      x = str.indexOf(cha, x + 1);
    }

    return x;
  }

  http.get(url, res => {
    let resData = '';
    res.setEncoding('utf8');
    res.on('data', chunk => resData += chunk);
    res.on('end', () => {
      const start_pos = resData.indexOf('window.Gbanners =') + 'window.Gbanners ='.length;
      const stop_pos = find(resData, '</script>', 3) - 2;  //resData.indexOf('</script>');
      let discoverData = resData.substring(start_pos, stop_pos);

      discoverData = discoverData.replace(/picUrl/g, '"picUrl"');
      discoverData = discoverData.replace(/url/g, '"url"');
      discoverData = discoverData.replace(/targetId/g, '"targetId"');
      discoverData = discoverData.replace(/backgroundUrl/g, '"backgroundUrl"');
      discoverData = discoverData.replace(/targetType/g, '"targetType"');

      cb(JSON.parse(discoverData));
    });
  });
}

源码比较长就不全部贴出来了,就列了两个代表性的函数,分别用到了

  • http.request(options[, callback])
  • http.get(options[, callback])

用于发起 http 请求抓取网易云音乐的数据,详细的用法转这里

总结

前后跨越的时间长度为4天,但实际码的时间也就十几个小时,除去正常上课大多数时间还是花在了网易云音乐的api上(神坑,要知道网易本身是没有开放什么云音乐这块的api的),主要参考着 GitHub 上大神的 python 代码,加上自己分析云音乐前端代码

疑问:网易既然没有开放 api并且还做了一些防护措施,但类似这样代码的存在是否有伤大雅(一方面没有压缩处理,再者暴露了一些数据和一点业务处理逻辑)

a:

b:

c:

Node方面

1.报文体中的数据是一段一段传输的(Buffer的经典使用场景)

所以就有必要拼接

let resData = '';

res.setEncoding('utf8');  // 针对中文的尿性
res.on('data', chunk => resData += chunk);

2.初尝 ES6 在 Node 中实践

  • let 声明一个变量,没有变量提升,具备块作用域
  • const 定义的是常量,同具备块作用域,用它定义变量之后就不能修改
  • 箭头函数,这个用的是挺爽的

学习更多的 ES6 特性还需深入,路漫漫...

微信方面

虽然是记一次微信公众号开发,但是到头来感觉学习到的更多是 Node 方面的知识,都不知道说什么好了,贴几张成果图吧

a:

b:

c:

个人订阅号是不支持自定义菜单,所以在测试号上玩的,至于自己的订阅号,顺便也配合做了下文字检索

欢迎关注测试 :

  • 订阅号名称: GoodTimeForYou
  • 订阅号微信号: h784124888