Vue实战 手写QQ音乐一(api接口搭建)

为了请求QQ音乐的数据时的跨域问题,我们使用Node.js + Express搭建一个中间件

可以直接在github: https://github.com/liaoqinwei/qqMusicApi 拔取源码

写的过程中借助文章 整理的接口(需要原生的qq音乐接口即可访问)https://blog.csdn.net/weixin_33874713/article/details/88003925

一、安装配置

npm install express 配置服务
npm install body-parser 解析参数
npm install fs 用于读取文件
npm install js-base64 base64解密
npm install mime mime参数类型解析

二、文件夹搭建

Vue实战 手写QQ音乐一(api接口搭建)_第1张图片

三、搭建工具文件Utils

promiseHttps.js

用于帮我们基于Promise发送Http/https请求、解析参数、配置请求头。

const https = require('https'),
    http = require('http');

/* 处理参数
 * url: 拼接的路径
 * param: 参数[Object]
 *  */
let urlHandler = (url, param = {}) => {
  let result = ''
  for (let key in param) {
    // 如果是自身属性, 避免遍历到原型
    if (param.hasOwnProperty(key)) {
      result += `&${key}=${param[key]}`
    }
  }
  return url.indexOf('?') > -1 ? `${url}&${result}` : `${url}?${result.slice(1)}`
}
/*
* 用于发送请求 返回一个promise实例
*
* */
let getData = (config = {}) => {
  // 没有传参就抛出异常
  if (Object.keys(config).length === 0) {
    throw new Error('Please pass in parameters !')
  }
  /* 解构参数:url请求地址 params请求参数 headers请求头信息 hostname请求的主机名 */
  let {url, params = {}, headers = {Connection: 'keep-alive', Accept: '*/*'}, hostname = 'c.y.qq.com'} = config,
      path = urlHandler(url, params), // 解析参数
      option = {
        hostname,
        path,
        headers
      }

  return new Promise((resolve) => {
    // 发送https请求
    https.get(option, res => {
      // 接收数据
      let chunk = ''
      // 数据是流传输 所以我们要监听 data 事件
      res.on('data', result => {
        // console.log(result)
        chunk += result + ''
      })
      // 数据传输完成触发end 数据完了我们执行 resolve 方法
      res.on('end', () => {
        resolve(chunk)
      })
    })
  })
}
/*
* 获取文件
* */
let getFile = url => {
  if (!url) return;
  return new Promise(resolve => {
    http.get(url, res => {
      let list = [], file
      // 我们用数组把所有的流 存储起来
      res.on('data', result => {
        list.push(result)
      })
      // 将所有的流 拼接成一个流 然后返回调用 resolve
      res.on('end', () => {
        file = Buffer.concat(list)
        resolve(file)
      })
    })
  })
}

module.exports = {getData, getFile}
promiseFS.js

帮助我们基于Promise读取文件

/*
* 将fs中的常用 I/O 操作封装为promise版本
* */

let fs = require('fs'),
    path = require('path'),
    resultObj = {};

let suffixHandle = (pathname) => {
  let suffixReg = /\.(PNG|JPG|JPEG|WEBP|ICO|BMP|SVG|MP4|MP3|M3U8|WAV|OGG)$/i
  return suffixReg.test(pathname)
}

// READ-FILE / READ-DIR / MK-DIR / RM-DIR / UN-LINK /
/*
* 读取文件时 需要使用编码 以及过滤 富媒体 文件
* */
['readFile', 'readdir', 'mkdir', 'rmdir', 'unlink'].forEach(item => {
  resultObj[item] = function (pathname, encoding = 'utf8') {
    return new Promise((resolve, reject) => {
      let callback = function (err, res) {
        !err ? resolve(res) : reject(err)
      }
      // 如果是富媒体编码就为null
      suffixHandle() ? encoding = null : null
      pathname = path.resolve(pathname)

      if (item !== 'readFile') {
        encoding = callback
        encoding = null
      }
      fs[item](pathname, encoding, callback)
    })
  }
});

// WRITE-FILE / APPEND-FILE
['writeFile', 'appendFile'].forEach(item => {
  resultObj[item] = function (pathname, content, encoding = 'utf8') {
    // 支持JSON类型数据
    (typeof content === 'object' && content !== null) ? content = JSON.stringify(content) : null
    // 将传入的内容转为 对象
    typeof content !== 'string' ? content += '' : null
    return new Promise((resolve, reject) => {
      let callback = function (err, res) {
        !err ? resolve(res) : reject(err)
      }
      pathname = path.resolve(pathname)
      fs[item](pathname, content, encoding, callback)
    })
  }
})

// COPYFILE
resultObj['copyFile'] = function (pathname1, pathname2) {
  return new Promise((resolve, reject) => {
    // 解析路径 为了防止路径错误
    pathname1 = path.resolve(pathname1)
    pathname2 = path.resolve(pathname2)

    let callback = function (err) {
      !err ? resolve() : reject(err)
    }

    fs['copyFile'](pathname1, pathname2, callback)
  })
}

module.exports = resultObj
parseSign.js

帮助我们请求歌词时加密必要的请求参数
由于该文件是从qq音乐请求中拿下来的,文件经过打包,并非作者所写,所以直接放上文件地址:https://github.com/liaoqinwei/qqMusicApi/blob/master/utils/parseSign.js
Vue实战 手写QQ音乐一(api接口搭建)_第2张图片

三、发送请求

request/index.js 请求移动端的数据

说明:当我们请求qq音乐的时候,移动端的数据会放在window.__INIT_DATA__中所以我们需要通过正则截取中间的数据为我们所用(我们将数据放在了json文件中)
Vue实战 手写QQ音乐一(api接口搭建)_第3张图片

let {getData} = require('../utils/promiseHttps'),
    {writeFile} = require('../utils/promiseFS');
// 移动端主页数据思路
// 我们把数据获取下来 通过 正则拆分数据
// 将数据保存到json/recommend.json 中
// 为了保证数据真实,我们需要每隔一分钟执行一次这个方法
let saveRecommendData = () => {
  getData({url: 'https://i.y.qq.com/n2/m/index.html'}).then(res => {
    let reg = /
                    
                    

你可能感兴趣的:(javascript,js,qq音乐,vue,nodejs,json,js,javascript)