续上一篇搭建音乐播放器桌面应用–前端篇后,这次讲述给界面提供数据包的后端扮演者–Node接入层。
Node在项目中扮演的是后端,但准确地说Node这并不是后端的角色,真正后端角色是豆瓣FM暴露的API。如下图
中间这一服务层即是本文的重点:对接口的挖取与封装。豆瓣FM官方并没对外提供API手册,尽管豆瓣提供了开放平台, 但与我们登录官方网站进行授权与操作走的并不是同一通道。
开放平台开放的类似于第三方登录 给开发者一个新的API Key,有了这个key而允许了我们对指定的功能进行指定的操作。这对于开发者是很受限的,因此我们需要采取各种可能的手段抓包,分析整合,整理出我们真正需要的接口。
上图中豆瓣FMAPI来源:https://douban.fm。
源码
三端如何分工
- 前端:界面布局,数据渲染
- 服务层(接入层):接口封装,功能拆分
- 后端(豆瓣FM接口):提供原始数据包
端与端之间如何交互
交互可分为前端与服务层的交互,以及服务层与后端的交互。
前端与服务层
在这两者之间我们需要思考几个问题
- 如何设计接口
- 接口应遵循哪些规范
- 提供哪些类型的接口
如何设计接口
我们采用RESTful API,它是目前比较成熟的一套API设计理论,事实上在工作中我接触到的后端接口也均是RESTful设计的API。RESTful API是面向资源的API设计架构,资源即为可供我们操作的数据群。结合我们这个项目,资源即为用户登录而获得用户的token,个人信息,爱心歌曲,歌曲歌词等。到此我们可以确定我们的API一半身形:/aaa 或者 /bbb ,这aaa 和 bbb 指的是资源位置。
接口遵循的规范:
路径:根据功能划分,播放器这个项目中我们分为两大部分功能,用户管理和歌曲管理,因此路径可能长这样:
12345678用户管理:/user/login: 登录/user/basic: 获取个人基本信息歌曲管理/song/next 下一首/song/like 点赞歌曲/song/lyric 获取歌词方法:
这个项目中我们只用到三种方法,GET,POST
- GET:用于资源获取,不做增删改查,如切换到粤语歌曲。
- POST:用于对资源修改或获取一些重要信息。如点赞歌曲,记录会存在个人账号里面;登录时获取token信息。
返回格式:
12345678{<!-- 失败:0 成功:1 -->"code": 1,"msg": "success", // failed"data" : {}}一个登陆API示例:
123456789101112131415161718192021登录- url: http://xxxxx/user/login- param: {username:13798994068,password:123456c}- method: get- return: {<!-- 失败:0 成功:1 -->"code": 1,"msg": "success", // failed"data" : {"access_token": "25a64943770f2dbca55d46995","douban_user_name": "abigaleyu","douban_user_id": "1688842","expires_in": 7775999,"refresh_token": "5f2388c502a9a4f0799f2f9"}}
服务层与豆瓣FM的交互
这一交互我们同样需要思考几个问题:
- 如何从豆瓣FM获取登录信息
- 个人账号下操作歌曲
- 如何根据接口规范封装接口
路径
从入口文件index.js中我们可以看到:
12345
const PORT = process.env.PORT || 8082;const server = express();server.use('/user', user);server.use('/song', song);
如何从豆瓣FM获取登录信息
从豆瓣FM获取登录信息占据了这层面工作量的70%,原因在与豆瓣FM的登陆是会重定向到豆瓣官网的登陆,需要多次重定向并且在不同的URL中读取header里的cookie并存下来,召集我们所需要的几个k-v之后才可以为所欲为,比如听自己喜欢的歌呀,点赞喜欢的歌曲呀~
文件 src/routes/user.js
中我们可以看到存在这一逻辑:
/login
—>/basic?username=xxx&password=xxx&token=xxx
–> getUserAc()
–> serveceAcount()
–> getDouBanFm()
–> getUserBid()
–> getUserAc()
这就是为了从多个重定向的header里面挖取到我们需要的cookie
/login获取到到access_token,官方请求如下:
|
|
获取个人基本信息,headers中需要加上以上获取的有效token
|
|
我们可以从返回结果中拿到我们要的基本信息
我们要找的key-value就藏在截图部分,从cookie里劫持下来,存到本地,再看一个截图,状态码是200而不是3开头,是因为这个basic的请求中,Request Headers有一行:Referer:https://accounts.douban.com/popup/login?source=fm&use_post_message
,有什么特殊的吗~可以看下下面的截图
关注Response Headers 里的Location,我们正需要从它调整的链接中去找下一个值。也正式因为它在Response中而非Request中,所以Status Code 为3开头。
具体获取过程可以查看src/routes/user.js
,总之我们最终需要集齐token,bid,dbcl12,ck这几个值,以下请求是我在登录状态下点击下一首歌曲浏览器显示的请求头,我们获取到的值就派上用场了~
接口封装
我们根据约定好的规范:方法,返回结果等进行文档梳理
登录态:我们分为初次登录和采用token登录
初次登录:即无token或token已过期
123456789101112131415161718## 登录- url: http://localhost:8082/user/login- param: {username: username,password: password}- method: post- return: {code: 1,msg: 'success',data: {access_token: '208e18axxxxxxxxx78ebf00a1',douban_user_name: 'abigaleyu',douban_user_id: '168889042',expires_in: 7775999,refresh_token: 'd9243263xxxxxxxx22a0b7eea'}}采用token登录:token未过期的条件下,我们可以重复利用它
12345678910111213141516171819202122- url: http://localhost:8082/user/loginByToken- param: {username:13798994068,token:xxxxxxx}- method: get- return: {<!-- 失败:0 成功:1 -->"code": 1,"msg": "success", // failed"data" : {<!-- 成功:1 -->"access_token": "25a64943770f2dbca55d46995","douban_user_name": "abigaleyu","douban_user_id": "1688842","expires_in": 7775999,"refresh_token": "5f2388c502a9a4f0799f2f9"}<!-- 失败 0 -->"code": -1,"msg": "failed"}我在Node接入层与豆瓣FM的交互中重点解释了登录逻辑,关于歌曲的获取,切换等方式可以参考登录API获取的步骤,它们会比登录简单的哟~
总结一下,Node实现的这一层为接入层,负责再次封装接口以及输出,也为我们做一些安全相关信息的保护,假如你需要做一些服务器同构渲染,很建议加入这样一层接入层