博主是第一次写博客,欢迎前来指正!

项目预览地址:http://dv20912014.iok.la  (这里重点强调一下,项目是使用花生壳内网穿透映射出去的,为什么要这样做下面我会做详细的解释,由于用的是花生壳,首次加载需要20秒时间,请不要再微信上打开“微信有限制”,最好把地址复制到浏览器打开
码云源码地址:https://gitee.com/citn/template-developer.git

 

vue学了大概是1个月多的时间,主要还是看视频学习的,视频是一位网友提供的,(轻声低语,疯狂暗示)他叫豆芽菜,<(* ̄▽ ̄*)/,这是重点 要记下来,写这个项目之前我是有看过慕课网上面有位老师(ustbhuangyi)讲的Vue 2.0开发企业级移动端音乐Web App的课程,课程也是豆芽菜提供的。在此非常非常的感谢豆芽菜!还有谜之家的小伙伴们!

 

本篇博客讲的是我实战这个项目每个接口以及传递的参数和我所遇到的坑,我只希望有和我一样在实战QQ音乐的人可以少遇到一点坑,项目实战花了将近1个多月的时间,大部分时间都是晚上下班搞一下,所有接口都能正常获取,下面我把我这次实战所学的的知识分享给大家!

 

技术栈

  • vue-cli
  • vuex
  • vue-router
  • mint-ui
  • axios
  • better-scroll
  • iconfont

 

项目部分页面截图

    

 

项目大致分为8个页面

  • 首页(推荐部分、排行榜部分、搜索部分)
  • 电台页面
  • 热门歌单列表页面
  • 排行榜页面
  • 歌手页面
  • 专辑页面
  • 视频页面
  • 无法搜索到歌曲页面

 

项目目录树桩结构分析图

 

API接口分析

接口我看了下  总共20个接口,下面我简单的讲解一下每个接口以及传递动态的参数,但是在这之前 我们需要在vue项目config/index.js路径配置反向代理,由于接口是官方的  想要拿到官方的数据  就必须通过反向代理解决跨域的问题。否则浏览器的控制台会出现下面这段报错(禁止非法跨域请求)

想要解决跨域问题,需要如下配置

配置方式(看下方图片):

跨域的有两个域名: https://c.y.qq.com是抓取非音频视频的数据(首页、搜索页、歌曲列表页等数据)对应的是 --> /api

                                 https://u.y.qq.com是抓取音频视频的数据  对应的是 --> /key

所以这两个域名都需要配置反向代理,在接口(getIndex.js)文件那边直接写配置好的/api/key路径  看下图

配置好以后我们就可以通过axios请求来抓取接口数据啦,跨域也因此解决,是不是看着特别简单呢哈哈哈,相对来说,我可是花了好长时间百度才找到的办法。慕课网视频上老师用的是jsonp  目前我这个项目用的是axios来抓取数据,因此会有些差距。

 

这里大家要记住  接口都是在vue/src/api/getIndex.js目录下(源码已经上传到码云,大家有空可以看一看)。下面我们来分析每一个接口

推荐部分接口分析

//推荐页接口
export function getRecomment(callback){
	axios('/api/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg',{
		params:{
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			_: 1545886811612
		}
	}).then(data=>{
		callback(data)
	}).catch(error=>{
		callback(error)
	})
}

首页推荐部分的接口比较简单,不需要传递任何动态的参数,都是一些固定参数,例如uin字段是账号,我们这块没用到登录,可以不必理会,下面是拿到的数据结构以及其呈现布局样式,成功加载数据的时候都会返回到callback回调函数里面,有点基础的同学都知道  接口需要传递一个回调函数,方便调用拿到的数据,下面我将不再提及callback回调函数。

页面标注(recomment.vue)

 

排行榜接口分析(排行榜的接口也是一样  直接抓取数据,不需要传递动态参数)

//排行榜接口
export function getRanking(callback){
	let date = new Date().getTime()
	axios('/api/v8/fcg-bin/fcg_myqq_toplist.fcg',{
		params:{
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			_: date,
		}
	}).then(data=>{
		callback(data)
	}).catch(error=>{
		callback(error)
	})
}

页面标注(ranking.vue)

 

热门搜索接口分析(热门搜索的接口也是一样  直接抓取数据,也是不需要传递动态参数的)

//热门搜索接口
export function getSearch(callback){
	let date = new Date().getTime()
	axios('/api/splcloud/fcgi-bin/gethotkey.fcg',{
		params:{
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			_: date
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	

页面标注(search.vue)

怎么样 很简单吧  下面要讲的接口是涉及到动态参数的

 

搜索列表接口分析

//搜索列表接口
export function getSearchSongList(w,p,callback){
	let date = new Date().getTime()
	axios('/api/soso/fcgi-bin/search_for_qq_cp',{
		params:{
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			w: w,
			zhidaqu: 1,
			catZhida: 1,
			t: 0,
			flag: 1,
			ie: 'utf-8',
			sem: 1,
			aggr: 0,
			perpage: 20,
			n: 20,
			p: p,
			remoteplace: 'txt.mqq.all',
			_: date
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

(上拉加载效果图)

getSearchsongList() 方法有两个比较重要的参数

w参数是输入框输入的内容(也就是要搜索的内容)

p参数是加载的页数,默认是第一页,首次加载传个1,再次就是上拉加载的时候,p++,每次上拉到底部都+1,如果没有数据就不再+1,重新刷新页面或者重新搜索内容的时候应该把p重置为1,这里默认是一次加载20条数据。

这里的上拉加载我用的是better-scroll插件,通过命令npm install --save better-scroll 就可以下载

然后在页面上引入

import BScroll from 'better-scroll'

better-scroll使用的方法也比较简单,这里我给出better-scroll的官方地址:http://ustbhuangyi.github.io/better-scroll/doc/zh-hans/

有兴趣的同学都可以去看一看,个人觉得better-scroll挺好用的,有上拉下拉事件以及滑动的弹性特效。

 

这里的搜索记录我用到了localStorage缓存,主要用来存储搜索的记录,如果有不懂localStorage用法的同学可以百度一下localStorage的用法,相信很快就可以学会的,这是再基础不过的东西了。因为我这边也没办法给你们详细的讲解,望理解一下哈,实在不行我就给你链接不就得了嘛  拿好了:https://www.cnblogs.com/ranyonsue/p/6402687.html

 

热门歌单列表接口分析

//热门歌单列表接口
export function getSongList(disstid,song_begin,callback){
	let date = new Date().getTime()
	axios('/api/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg',{
		params:{
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			new_format: 1,
			pic: 500,
			disstid: disstid,
			type: 1,
			json: 1,
			utf8: 1,
			onlysong: 0,
			picmid: 1,
			nosign: 1,
			song_begin: song_begin,
			song_num: 15,
			_: date
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

此处是首页推荐部分的热门歌单点进去的歌单列表页面接口,这个接口有两个动态的参数,disstid和song_begin,我这里先讲讲disstid,在我们通过首页接口拿到的数据是这样的

每一条数据中都有一个唯一值id,拿到数据中的id然后通过url传递到gedanlist.vue页面通过vue-router传递过去

然后在gedanlist.vue页面中接收传过来的id

还有一个参数就是song_begin,song_begin参数是用来加载数据的,首次传参是0,因为这个页面涉及到点击加载更多的按钮

点击加载更多歌曲以后则把song_begin+15传递到后台,规则是这样的,首次加载数据是0,依次0-->15-->30-->35每次叠加15,如果数据加载完成拿不到数据,证明数据已经全部加载完成。

拿到的数据格式是这样子的

 

这里除了vip歌曲都是可以点击播放的,点击播放需要调用如下接口

//获得songmid传过来获取对应的vkey  其实purl就是播放源了  拿到purl就可以了  可以不执行getVideo接口
export function getvkey(songmid,callback){
	axios.defaults.transformRequest = [function (data) {
	    let ret = ''
	    for (let it in data) {
	      ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
	    }
	    return ret
	}]
	let date = new Date().getTime()
	axios({
	  url:'/vkey/cgi-bin/musicu.fcg?_='+date,
	  method: 'post',
	  data: {
	  	
	  },
	  transformRequest: [function () {
	  	return `{"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"8326724064","songmid":${songmid},"songtype":[],"uin":"0","loginflag":0,"platform":"23","h5to":"speed"}},"comm":{"g_tk":5381,"uin":0,"format":"json","ct":23,"cv":0}}`
	  }],
	  headers: {
	    'Content-Type': 'application/x-www-form-urlencoded'
	  }
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

getvkey()方法,参数songmid是一个数组,因为gedanlist.vue页面加载的歌曲是多条,因此每一条歌曲对应的id需要封装成数组,然后转成字符串传递到后台拿到播放源地址

 成功拿到播放源地址

播放源地址是动态成功的,每次刷新页面拿到的播放源地址都是不一样的

 

获取歌词接口分析


//获取歌词接口
export function getLyric(musicid,callback){
	let date = new Date().getTime()
	axios('/api/lyric/fcgi-bin/fcg_query_lyric.fcg',{
		params:{
			g_tk: 5381,
			uin: 0,
			format: 'jsonp',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			nobase64: 1,
			musicid: musicid,
			songtype: 0,
			_: date,
			jsonpCallback: 'jsonp'
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

getLyric()方法需要传递musicid参数,musicid是在热门歌单列表接口中拿到的,如下图所示

 

正常拿到歌词的格式:

歌词获取成功以后需要解析,我这里用的是html标签进行解析,先把拿到的歌词存进标签内,因为html标签是可以把歌词转义的

转移以后的数据格式如下图所示:

时间和歌词并排显示出来了,这个时候我们就需要把歌词进行拆分,时间和歌词拆分出来,这里我先强调一下,其实可以用vue-player插件做播放器的,而且还不需要做歌词拆分,把歌词放进vue-player定义的歌词变量即可,这我也是开发完以后才得知,不过我还是按照我的思路来讲解。这边我定义了两个歌词和时间拆分方法,先看下方图片

我这里先把转义后的歌词时间转换成字符串toString()方法,然后用正则表达式+字符串切割方法split()把歌词进行拆分出来

时间拆分也是一样,时间拆分以后是[00:00.93]这种格式的,我这里需要把时间转换成单位秒才可以计算音频播放的进度进行歌词滚动,然后我写了timeTmm()方法将[00:00.93]这种格式的时间转换成单位秒再return回来。歌词滚动这部分我没用到better-scroll,歌词滚动用的是css3的动画,transform和transition动画效果。需要详细了解的同学可以认真看看我写的代码。不懂邮箱回复1666584574@qq.com

歌词和时间拆分以后存进数组里,然后格式如下

lyric是歌词,time是秒数,监听音频播放超过歌词的秒数就往上滚动28px,看起来是不是很简单呢,看着简单还是得实际操作一下才知道哈,实敲才是真!学代码主要还是兴趣,兴趣是学习编程最好的老师,如果有自学的同学,把技术看成是兴趣,我相信你能坚持下去的,因为我也是自学的,工作也一年有余,不懂的同学记得邮箱联系我!彼此分享学习经验享受学习这个过程(有些过程是痛苦的哈哈哈)

 

当然啦  你们应该会发现有些页面会出现作者的信息  这是封装好的copyright页面。封装好以后只需要在每个页面调用copyright-rohlin标签就能显示出来了

封装方法如下,先创建一个copyright文件夹,里面分别有两个文件,copyright.vue和index.js

(copyright.vue页面)

然后在copyright新建一个index.js文件去调用Vue.component方法引入copyright.vue页面,Vue.component方法第一个参数可以给页面自定义标签名称,第二个参数则是引入的页面。

在src/main.js调用copyright/index.js,通过Vue.use()引入自定义的页面

完成上述操作以后就可以在页面中使用自定义页面啦,也可以使用slot插槽自己封装插件哦!

 

排行榜歌单列表接口分析

//排行榜歌单列表接口
export function getToplist(topid,callback){
	let date = new Date().getTime()
	axios('/api/v8/fcg-bin/fcg_v8_toplist_cp.fcg',{
		params:{
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			tpl: 3,
			page: 'detail',
			type: 'top',
			topid: topid,
			_: date
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

getToplist()方法有topid参数,下面我们来看一下排行榜页面(ranking,vue),排行榜拿到的数据格式是这样的

我们需要把排行榜接口的id传递到排行榜歌单列表页面(toplist.vue),通过vue-router插件,点击以后跳转传递参数

在toplist.vue页面接收传过来的id,getToplist()方法有topid参数也正是传过来的id,正常拿到数据格式如下:

页面标注(toplist.vue)

有些歌词是需要vip  有标注vip的是无法拿到播放源地址的,所以点击vip歌曲的时候禁止播放并弹出提示,判断vip歌曲是拿到的数据里面有字段是payplay == 1 的时候就是付费歌曲。看下图

 

想要拿到音频播放源和歌词的接口也跟gedanlist.vue页面一样,getLyric()方法和getvkey()方法,调用接口的方法是同一个,上面有讲

 

搜索歌单列表接口

这个接口是singer.vue页面的,比如我们在搜索栏搜索林俊杰,薛之谦等明星,都是跳转到singer.vue页面

//搜索歌单列表接口
export function getSinger(singermid,begin,callback){
	let date = new Date().getTime()

	axios('/api/v8/fcg-bin/fcg_v8_singer_track_cp.fcg',{
		params:{
			singermid: singermid,
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5page',
			needNewCode: 1,
			order: 'listen',
			from: 'h5',
			num: 15,
			begin: begin,
			_: date
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

getSinger()方法有两个参数,singermid参数是搜索页传过来的id

begin字段也就是页数,首次加载默认值是0,点击加载更多歌曲则传递的是15,依次点击加载更多歌曲累计叠加15,  0-->15-->30-->45直到数据加载完成将不再叠加

 

最新专辑跳转的是album.vue页面,需要传递albummid(专辑id),专辑页面加载的接口如下

//专辑歌单接口
export function getAlbum(albummid,callback){
	let date = new Date().getTime()
	axios('/api/v8/fcg-bin/fcg_v8_album_info_cp.fcg',{
		params:{
			albummid:albummid,
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			_: date
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

拿到的数据格式如下

页面标注(album.vue)

 


//获取评论接口
export function getreplay(topid,callback){
	let date = new Date().getTime()
	axios('/api/base/fcgi-bin/fcg_global_comment_h5.fcg',{
		params:{
			g_tk: 959037872,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			cid: 205360772,
			reqtype: 1,
			cmd: 8,
			needmusiccrit: 0,
			pagesize: 3,
			lasthotcommentid: 0,
			qq: 0,
			msg_comment_id:'' ,
			pagenum: 0,
			biztype: 1,
			topid: topid,
			ct: 999,
			_: date
		},
		headers:{
			'content-type': 'application/json;charset=utf-8'
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

album.vue页面还有加载评论的接口,getreplay()方法的topid参数是url传递过来的id,同加载album.vue页面加载所用到的(albummid)参数一致

 

视频接口分析

//获取歌曲视频
export function getmv(vid,callback){
	let date = new Date().getTime()
	axios('/vkey/cgi-bin/musicu.fcg',{
		params:{
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			data: `{"getMVInfo":{"module":"video.VideoDataServer","method":"get_video_info_batch","param":{"vidlist":["${vid}"],"required":["vid","type","name","singers","playcnt","pubdate","uploader_headurl","uploader_nick","uploader_encuin","uploader_uin","uploader_follower_num","uploader_hasfollow","from","isfav","video_switch","desc","sid","gmid","cover_pic_medium"]}},"getToplistInfo":{"module":"video.VideoLogicServer","method":"get_hitlist_info","param":{"vid":"${vid}"}},"getRecomMV":{"module":"video.VideoLogicServer","method":"rec_video_byvid","param":{"vid":"${vid}","required":["vid","type","cover_pic_medium","name","singers","uploader_nick","playcnt"],"support":1}}}`,
					
			_: date
		},
		headers:{
			'content-type': 'text/plain; charset=utf-8'
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

getmv()方法,vid参数用于加载视频的必须字段,vid在singer.vue页面的接口数据中获取,数据格式如下

 

在singer.vue页面通过vue-router传递到mv.vue页面,拿到vid以后调用接口成功拿到视频数据

 

视频播放地址:

 

我们还有额外的两个接口是获取视频评论和详情数据,视频详情的接口是如下代码,也是通过vid去获取的

//获取视频详情
export function getplaysongVideoUrl(vid,callback){
	let date = new Date().getTime()
	axios('/vkey/cgi-bin/musicu.fcg',{
		params:{
			g_tk: 5381,
			uin: 0,
			ct: 23,
			cv: 0,
			format: 'json',
			callback: 'qmv_jsonp_6',
			data: `{"getMVInfo":{"module":"video.VideoDataServer","method":"get_video_info_batch","param":{"vidlist":["${vid}"],"required":["vid","sid","gmid","type","name","cover_pic","video_switch","msg"],"from":"h5.playsong"}},"getMVUrl":{"module":"gosrf.Stream.MvUrlProxy","method":"GetMvUrls","param":{"vids":["${vid}"],"from":"h5.playsong"},"request_typet":10001}}`,
			_: date
		},
		headers:{
			'content-type': 'text/plain; charset=utf-8'
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

详情数据格式如下:

 

然后就是视频评论接口

//获取视频评论接口
export function getmvreplay(topid,biztype,callback){
	let date = new Date().getTime()
	axios('/api/base/fcgi-bin/fcg_global_comment_h5.fcg',{
		params:{
			g_tk: 1856849048,
			uin: 1666584574,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			cid: 205360772,
			reqtype: 1,
			cmd: 8,
			needmusiccrit: 0,
			pagesize: 10,
			lasthotcommentid: 0,
			qq: 1666584574,
			msg_comment_id: '',
			pagenum: 0,
			biztype: biztype,
			topid: topid,
			ct: 888,
			_: date
		},
		headers:{
			'content-type': 'application/json;charset=utf-8'
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

getmvreplay()方法有两个参数,topid和biztype

topid其实就是vid,这里大家不要误解了,只是换了个变量名,biztype是用来判断是否是mv标志的视频,如果是mv标志的视频,则传一个5,如果不是mv标志的视频,就传一个31,这里一定要正确传参,不然是加载不出评论的哦

判断是否是mv标志的视频可以在数据中看到有type是否等于0,如果等于0那么就是mv视频。

 

电台音频列表接口分析

 

我们先来看张图,这里是我遇到最坑的地方,可能是由于个人经验不足的缘故,下面我们来看一下

在首页可以看到有电台列表,当我们点击电台的时候是跳转到playsong.vue页面,playsong.vue页面是20首随机播放的歌曲,也就是说每次点击电台进去以后播放的歌曲是不一样的,需要通过url把20首歌曲的id传递过去,我当时比较纳闷,url的参数从哪里来,将近找了好长时间才找到(花了2个晚上的时间,技术太水木有办法,低调低调),其实点击的时候是会发起请求的,我当时是把network调整到3G网才看到的请求,当我们点击电台的时候,就会立马发起一个请求,从后端拿到20条歌曲的id再通过url传递过去

 

电台20首随机歌曲接口

//获取电台音频列表 随机20条
export function getradiosonglist(callback){
	let date = new Date().getTime()
	axios('/api/v8/fcg-bin/fcg_v8_radiosonglist.fcg',{
		params:{
			labelid: 199,
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			_: date
		},
		headers:{
			'content-type': 'text/plain; charset=utf-8'
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

getradiosonglist()方法可以拿到随机的20条歌曲,歌曲下面有id,把id存进数组,用JSON.stringify(数组)方法把数组转成字符串,然后通过url传递过去

20条电台歌曲id传递到playsong.vue页面以后,我们通过JSON.parse(字符串)方法把字符串数组转回数组,然后从数组中取出第一个值再调用如下接口拿到页面中的数据

//歌曲详情接口  视频、音乐
export function getmusicu(songid,callback){
	axios.defaults.transformRequest = [function (data) {
	    let ret = ''
	    for (let it in data) {
	      ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
	    }
	    return ret
	}]
	let date = new Date().getTime()
	axios({
	  url: '/vkey/cgi-bin/musicu.fcg?_='+date,
	  method: 'post',
	  data: {
	  	
	  },
	  transformRequest: [function () {
	  	return `{"comm":{"g_tk":5381,"uin":1666584574,"format":"json","inCharset":"utf-8","outCharset":"utf-8","notice":0,"platform":"h5","needNewCode":1},"detail":{"module":"music.pf_song_detail_svr","method":"get_song_detail","param":{"song_id":${songid}}},"simsongs":{"module":"rcmusic.similarSongRadioServer","method":"get_simsongs","param":{"songid":${songid}}},"gedan":{"module":"music.mb_gedan_recommend_svr","method":"get_related_gedan","param":{"sin":0,"last_id":0,"song_type":1,"song_id":${songid}}},"video":{"module":"MvService.MvInfoProServer","method":"GetSongRelatedMv","param":{"songid":"${songid}","songtype":1,"lastmvid":0,"num":5}}}`
	  }],
	  headers: {
	    'Content-Type': 'application/x-www-form-urlencoded'
	  }
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

 

 

想要播放playsong.vue页面的歌曲我们需要调用额外的接口,说到这里,为什么叫额外的呢,因为我怎么也找不到移动端QQ音乐的音频播放源是怎么拿到的,请求中并找不到,如果有找到的同学可以来跟我一起讨论。所以采用了另外一种手段,就是查看QQ音乐官方pc端的接口,既然移动端看不出端倪那我看pc端还不行吗,果然不出我所料,pc端有请求播放源的接口,接口方法如下

//获取音频vkey(获取的purl是完整链接)接口
export function getaudiovkey(songmid,callback){
	axios('/vkey/cgi-bin/musicu.fcg',{
		params:{
			'-':'getplaysongvkey18692067669581247',
			g_tk: 5381,
			loginUin: 0,
			hostUin: 0,
			format: 'json',
			inCharset: 'utf8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'yqq.json',
			needNewCode: 0,
			data:`{"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch","param":{"guid":"1595362978","calltype":0,"userip":""}},"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"1595362978","songmid":["${songmid}"],"songtype":[0],"uin":"0","loginflag":1,"platform":"20"}},"comm":{"uin":0,"format":"json","ct":20,"cv":0}}`
		},
		headers:{
			'content-type': 'text/plain; charset=utf-8'
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

 

getaudiovkey()方法的接口我们可以看到,也是需要传递songmid参数,拿到的数据如下图所示:

 

这里我要讲一下,vkey是音频地址中的vkey参数,这里我们使用完整的purl字段就行了,仔细看一下purl字段里面是包含vkey的

 

获取专辑评论接口

//获取评论接口
export function getalbumreplay(topid,callback){
	let date = new Date().getTime()
	axios('/api/base/fcgi-bin/fcg_global_comment_h5.fcg',{
		params:{
			g_tk: 959037872,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			cid: 205360772,
			reqtype: 1,
			cmd: 6,
			needmusiccrit: 0,
			pagesize: 10,
			lasthotcommentid: 0,
			qq: 0,
			msg_comment_id:'' ,
			pagenum: 0,
			biztype: 2,
			topid: topid,
			ct: 888,
			_: date
		},
		headers:{
			'content-type': 'application/json;charset=utf-8'
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

getalbumreplay()方法有topid参数,topid参数也正是传递过来的songmid字段,成功拿到数据格式如下

 

歌手与专辑接口

//专辑其他歌单接口
export function getOtherAlbum(albummid,callback){
	let date = new Date().getTime()
	axios('/api/v8/fcg-bin/fcg_v8_album_info_cp.fcg',{
		params:{
			albumid:albummid,
			g_tk: 5381,
			uin: 0,
			format: 'json',
			inCharset: 'utf-8',
			outCharset: 'utf-8',
			notice: 0,
			platform: 'h5',
			needNewCode: 1,
			_: date
		}
	}).then(response=>{
		callback(response)
	}).catch(error=>{
		callback(error)
	})
}

这个接口加载的是playsong.vue页面如下图所示的数据

 

getOtherAlbum()方法需要传递albummid参数,albummid参数是通过上面我所说的getaudiovkey()方法调用的数据所拿到,也就是mid

 


到现在,所有接口都讲完了,大家在预览项目的时候(项目地址 http://dv20912014.iok.la),首次加载会特别慢,最少需要将近20秒的时间,这个原因具体我也不是很清楚,至于我为什么要使用花生壳,为什么不打包呢。其实我们在安装vue-cli的时候  是附带webpack+node+vue的,我们所有接口的跨域都是需要在config/index.js文件下配置一些信息(反向代理),如果不配置反向代理,那么控制台就会提示禁止跨域的报错,当我们把vue项目打包以后,就没有webpack+node的支撑,打包以后通常是html,js,css,img等文件,想要实现打包以后解决跨域的问题,就需要在服务器用到nginx反向代理,这种方式我尝试过,只因无果,为什么这样说呢,可能是因为官方的限制,我将项目打包以后再服务器配置nginx反向代理以后,控制台没有提示跨域,首页的接口都能正常访问,但是有一部分接口是后端直接给你正常返回禁止跨域访问,具体是通过什么拦截的我也不是很清楚,比如搜索页面的接口,看下面图片

禁止跨域访问,脑壳疼,所以目前只能用花生壳把项目从内网映射出去啦,还有一点我要说一下,我这边花生壳是每个月2G,你们可要省着点用啊(手动滑稽),当然你们也可以直接下载码云上面的源码,npm run dev运行以后通过localhost:8080访问即可。

运行不起来的可以直接联系我本人邮箱:1666584574@qq.com

在此我创建了一个前端技术讨论交流群(个人的无任何广告也不是培训机构),有兴趣的同学都可以一起加入,QQ群号:280383111

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐