網易雲音樂API-music

一直以來都在關注nodejs,直到最近空閒下來,才嘗試寫寫nodejs小demo。文章若有錯誤歡迎批評指正!來自一位不知名的前端。

前言(本項目僅供學習使用)

一、本demo剛開始採用koa2開發,後面因爲koa2的異步響應很差處理(還在研究中)改用express;後續會嘗試使用koa2改造。
二、http請求(csrf僞造)主要參考netmusic-node;其餘部分思路參考NeteaseCloudMusicApi
三、本項目預覽地址https://music.jeeas.cn/html


已實現網易雲音樂基礎功能和websocket數據推送

以get方式請求
        一、搜索歌曲名 params[s=歌曲名,type,offset,limit]
          getApi/search?s=歌曲名

        二、單曲播放地址 params[id=歌曲id,br]
          getApi/music/url?id=25643093

        三、歌詞 params[id]
          getApi/lyric?id=25643093
        
        四、單曲詳情 params[id]
          getApi/music/detail?id=25643093

        五、專輯詳情 params[id] 
          getApi/album/detail?id=2263164

        六、歌單類型列表 params[]
          getApi/playlist/catlist
        
        七、歌單類型列表-熱門類型 params[] 
          getApi/playlist/hot
        
        八、推薦新音樂 params[] 
          getApi/personalized/newsong

        九、搜索hot params[]
          getApi/search/hot

        十、推薦歌單 params[] 
          getApi/personalized

package.json主要包說明

"dependencies": {
    "apicache": "^1.5.2",
    "big-integer": "^1.6.47",
    "crypto": "^1.0.1",
    "ejs": "^2.7.1",
    "express": "^4.17.1",
    "express-rate-limit": "^3.5.3",
    "fs-extra": "^8.1.0",
    "redis": "^2.8.0",
    "request": "^2.88.0",
    "socket.io": "~2.1.1"
  }

apicache:請求cache緩存,防止api調用過於頻繁ip被禁掉
ejs:數據模板
express-rate-limit:express內部封裝api訪問限制
redis:數據臨時存儲到redis中未涉及到數據庫操做
socket.io:socket基礎包前端

項目主入口

server.js
項目啓動後redis的鏈接狀態以及soketIo會掛載在整個server下,方便後面調用。node

...

var redisClient = false;
var ioSocket = null;
//啓動查看redis狀態
redis.initRedis(function(client) {
    redisClient = client && client != '' && client != null ? true : false;
    io.redisClient = redisClient;
});

...
socketServer.initServer(io);
//static
//api訪問限制20s內60次
//cache 緩存2分鐘  2 minutes  0.05 minutes=3s
//設置跨域訪問
//使用ejs
//使用路由
app.use(router);
...

server.listen(port, () => {
    console.log('Socket Server listening at port %d', port);
    console.log('Visit http://127.0.0.1:%d', port);
    console.log('Hello, I\'m %s, how can I help?', serverName);
});

http.js
項目http請求簡單封裝git

var http = require('http');

...
function WebAPI(options, callback) {
    //....
    var httpClients = http.request({
        hostname: 'music.163.com',
        method: method,
        path: options.path,
        headers: {...}
    },function(req, res) {
        req.on('error', function(err) {
            //請求異常處理...
        });
        req.on('data', function(chunk) {
            //獲取數據...
        });
        req.on('end', function() {
            //網易雲api調用有時候會響應爲空,爲空時從新發起請求
            //數據接收完畢處理rsp 
            //回調以前用websoket向全部clients廣播消息,以及更新redis
            callback(rsp);
        })
        
    });
    //網易雲csrf僞造,詳情crypto.js
    httpClients.write('params=' + cryptoreq.params +    '&encSecKey=' + cryptoreq.encSecKey);
    httpClients.end();

}
...

module.exports = {
    WebAPI: WebAPI,
}

socket.jsgithub

服務端接收clients的消息發送,以及向全部clients廣播消息(api調用數)web

function initServer(io,callback) {
    if (io) {
        io.on('connection', function(socket) {
            socket.on('message', function(data) {
                console.log(data.message)
            });
            //console.log('emit全部人推送,broadcast除某個套接字之外的全部人發送消息,eg:connection不推送');
            //向全部鏈接推送news消息
            socket.broadcast.emit('news', {
                message: 'a new connection',
                newsType: 'server-prop'
            });
            if(callback){
                callback(socket)
            }

            socket.on('disconnect', function() {
                //console.log('disconnect')
            });
        });
    }

}

module.exports = {
    initServer: initServer
};

redis.js
redis簡單的查詢更新封裝redis

var redis = require('redis');
var client = null;

function initRedis(callback) {
    if (!client) {
        client = redis.createClient(6379, '127.0.0.1');
    }
    client.on('connect', function() {
        //redis鏈接成功
        console.log('redis connect success!');
        if (callback) {
            callback(client);
        }

    });
    let first = true;
    client.on('error', function() {
        //redis鏈接失敗
        console.log('redis connect error!');
        if (callback && first == true) {
            first = false;
            callback(null);
        }
    });

};

function hmSet(options, callback) {
    if (client) {
        client.hmset(options.apiType, options.apiName, options.total);
        //redis簡單的使用(設置keys的值)
    }
}

function hgetAll(keys, callback, isTotal) {
    if (client) {
        client.hgetall(keys, function(err, obj) {
            //redis簡單的使用(查詢全部keys)
        });
    }
}

function getApiNumber(res) {
    //簡單計算api調用總數
}

module.exports = {
    hmSet: hmSet,
    hgetAll: hgetAll,
    initRedis: initRedis
};
基礎功能瞭解差很少以後,重點介紹一下routes.js路由內部的API封裝,也是整個demo部署的比較核心部分。外部公開的API以http(GET方式)爲主,本次以Socket調用(內部)示例,大致分享一下本身的心得體會。

routes.js路由

routes.js數據庫

ejs使用說明須要在server.js入口配置
app.set('views', path.join(__dirname, './views'));
app.set("view engine", "ejs");express

const express = require('express');
const router = express.Router();
const version = "/v1";
...
router.get('/music', function(request, response) {
    //監聽路由路由/music訪問
    //console.log(request.query)
    //模板使用ejs,response須要設置type,不然會以ejs源碼展現
    response.type('html');
    
    
    //經常使用模式 response.render(路由模板,回傳頁面參數)
    //此時會查找ejs的配置,view/music.ejs
    response.render('music', {
        title: '網易雲音樂Cloud',
        keywords:Tools.randomSongs()//隨機取一首歌曲名稱搜索
    })
    
    //在music.ejs模板中能夠<%= title %> <%= keywords %> 使用變量
});

/*
 **
 ** 一、搜索歌曲名
 **    params[s=歌曲名,type,offset,limit]
 **    /search?s=大城小愛
 **
 */
router.get(version + '/search', function(request, response) {
    //type:1: 單曲, 10: 專輯, 100: 歌手, 1000: 歌單, 1002: 用戶, 1004: MV, 1006: 歌詞, 1009: 電臺, 1014: 視頻
    //offset : 偏移數量,用於分頁 , 如 : 如 :( 頁數 -1)*20, 其中20爲limit的值,默認爲0
    var data = {
        s: decodeURI(request.query.s) || '',
        offset: request.query.offset || 0,
        limit: request.query.limit || 20,
        type: request.query.type || 1
    };
    var params = {
        path: '/weapi/cloudsearch/get/web',
        request: request,
        response: response,
        data: data,
        apiType: '1'
    };
    //在WebAPI內部response.send響應web數據
    Tools.WebAPI(params)
});
...
module.exports = router;

而後將router.js掛載在server.js下,整個已配置的路由即可以訪問
demo剛開始使用koa2做爲服務端的框架,後續由於router.get(xx,function(request, response) { 內部response異步響應很差處理(初學者才疏學淺,很是抱歉,能夠一塊兒探討),改用express處理異步響應。})json

網易雲API的請求訪問方式,能夠抓包或者網易雲音樂官網搜索慢慢摸索查看,固然也能夠借鑑別人的勞動成果!

心得體會編寫中
相關文章
相關標籤/搜索