上一篇文章基本上是流水账,就在这篇文章内详细介绍我的开发流程吧。

求点赞、求点赞、求点赞。

项目介绍

非常感谢(☆ω☆)

之前记的流水账,也可以结合一起看。

关于为什么写这篇文章呢,是为了开拓思维。现在好多东西都可以在网上搜到教程了,但又出现了一个新问题就是:“会者不难,难者不会”,思路有时候比具体的知识更重要。
我写这篇文章也是作为我自己的备忘录。毕竟过几天我就可能忘了我当初是怎么实现xx了。

比赛要求

1.基于云开发平台开发任意形式的Web应用
2.参赛应用本身也要有自己的前后端通信和数据库操作
可以找同学帮忙,但最终交作业的名义是你自己的。
大概就这些吧。

项目情况

我的项目为:网易云音乐模仿 QQ 音乐网页版界面
先“简单”介绍下我所完成的项目吧。

萌新小白作品,可能有些地方看起来很傻,见笑了。

演示:
演示
workbench

key.coldark.cn
music.coldark.cn
api.coldark.cn

这三项目作为一个整体来成为我的作品。
key:密钥登录界面
music:音乐播放界面
api:作为音乐播放界面播放音乐时调用的api

其实加上一个发卡站就完美了,但涉及到盈利就属于灰色地带了,违反了比赛的要求。
(其实是我压根不会弄nodejs版的发卡站)

开发经历

以下过程可能有点流水账,建议当小说看吧。

确认需求

老师的要求是在云开发平台开发,则就是在workbench上的cloudide开发,可以部署到serverless。
作为比赛项目,有两种类型:严肃和娱乐。考虑到涉及点赞,如果是严肃类风格的话可能用户并不会感兴趣。参考那些演讲台下观众昏昏欲睡,因此我只能选择娱乐类。
而作为载体。有文字、音频、视频、图片这几种选择,还有游戏。在最开始的时候我没考虑到有api从“大厂”那盗链。作为个人用户,直接通过阿里云给用户音频、视频、图片服务带宽费我直接扛不起,因此在最开始的时候就忽略了这三个选项。
而文字一般是小说之类的东西,但小说这个涉及到盗版了。除了小说,涉及文字的比较火热的就是查题之类的。再就是小而美的:国标,文书这类。
因此我总结了一下我所选择的东西的特点:
成本:消耗的性能相对较少,使用的流量必须忽略不计。
网络:更能发挥severless多地域的部署的优点。
瞬时性能:能展现serverless可以动态扩容优势
突出与众不同、差异化竞争:很多人会选择搭建博客、电子相框。
因此我的首选就是游戏。正好我玩过游戏有过因为玩家都聚集在一个区域而导致游戏紧急维护的情况。

确认优劣

我的劣势是完全不熟悉serverless平台,对于nodejs完全是小白,python的话只有写脚本的水平,还不至于能独立做一个网站,优势是熟悉网站运营,了解用户需要什么,市面上有哪些比较热门网站,因此我可以往我的优势发挥,使用开源、热门的项目。

确认项目

最开始的时候我是准备部署一个html小游戏就行了,所有内容全前端完成。
刚好在mjj论坛看到一个魔塔项目,因此参考老师部署静态文件的教程部署到服务器上了:

但在某次课程结束后,老师说要前后端通信,以及用到数据库。大概网站我是没时间也没能力了,因此暂时放弃了,大家想玩可以去找安装包玩玩。
(原准备开个服务器给大家玩玩的,但是忘记同步Git了(那个时候不会,后面会了又忘了),现在打开容器的时候发现容器已经被清空了。)
我再到GITHUB 以:game nodejs为关键词搜索,most stars排序。之所以用GitHub而不用谷歌搜是为了排除那些“商业项目”。
根据我谷歌搜到的内容,以nodejs作后端的游戏其实挺少的。果然前两页项目基本上只有几百star。
我再打开每个项目,看它的demo以及readme文件来查看是否符合我的选择。以下是我部分筛选项目以及评估。

FreezingMoon/AncientBeast :需要两个人在计算机前玩,更偏向西化
alexa/skill-sample-nodejs-adventure-game:文字冒险类游戏,用户不好迅速体验
jondubois/iogrid:nodejs版本太老了
Jerenaux/phaserquest 介绍了如何连接mongoDB
luin/CodeGame 技术上太难实现了
Lallassu/wizardwarz 鼠标控制不方便
gustaYo/vue-chess 国际象棋太小众了
node-pinus/pinus 国人项目,没demo
lance-gg/lance:作者写了个很好的入门教程:http://docs.lance.gg/tutorial-MyFirstGame.html

我还用3D+nodejs作为关键词搜了一遍。找到了个挺好玩的项目:https://github.com/konaraddi/web-riimote在本地虚拟机部署成功,但在cloudide部署失败了。和群里讨论了后感觉是因为它的客户端和服务器是使用TCP这类4层协议(不太确定),但为了节省时间我就没继续测试了,以后有机会再看看吧。

最后准备使用:colyseus/colyseus为基础的damian-pastorini/reldens
damian-pastorini/reldens前端与后端使用WebSocket 进行通信,并且后端还连接了数据库,部署的demo也还不错

在搜资料的过程中我还发现了一个他总结了他参加腾讯云serverless项目的网站,但因为我已经确定了项目因此就没详细的看他的项目了。

https://serverlesscloud.cn/blog/page/4

新的思路

在筛选合适的游戏项目的时候,因为老师说可以找同学帮忙,因此我询问了一圈我的做网站朋友和实验室的朋友们,但他们都没怎么接触过nodejs。ucw大佬高三要上课,没时间时间。虽然他推荐了个人给我但我想着将其作为最后一道保险吧。
最后我决定独自一人完成项目开发。大不了通宵几天

在找帮助的过程中,有个朋友和我聊天说他想部署一个项目:https://github.com/maomao1996/Vue-mmPlayer
而我在看玩这个项目的readme后才意识到,我可以使用api来获取大厂的资源,作为我自己的资源提供服务。(只要不盈利就没事),刚好Vue-mmPlayer以及api服务器的NeteaseCloudMusicApi都是国人的项目,并且项目维护时间比较久,还有群方便请教问题。只不过那时我以及确定部署游戏了。为了以防万一我还是将Vue-mmPlayer假如我的备用项目内。

部署前

damian-pastorini/reldens

这个项目的readme讲的非常详细,我照着它的readme就成功在虚拟机内跑通了,并且感觉瞬间高端起来。
演示如下
damian-pastorini/reldens演示

但是,它的编译文件不包含数据库配置信息,尝试整体部署到serverless时碰到了限制50M,大小限制,因此只能放弃部署,顶多以后再试。

Vue-mmPlayer

damian-pastorini/reldens部署失败后,我就开始着手部署Vue-mmPlayer了,虽然借用大厂的api的项目都能可以很好的解决昂贵的音视频资源的问题,但我没时间一个个找了。因此就直接选择Vue-mmPlayer。

部署中

网易云音乐模仿 QQ 音乐网页版界面本质上是前端:Vue-mmPlayer + 后端:NeteaseCloudMusicApi
符合前后端通信这个要求,但原项目并不需要对接数据库,因此我为了对接数据库,加了个前端,参考那行“VIP盗版网站"它们的思路,在最前面加了一个验证网站,播放界面通过referer判断来源域名,来实现是否可以播放还是跳转到授权页面。

测试

我首先在自己的服务器上进行了测试,参考了源项目的部署教程,在自己的服务器上部署,来熟悉流程和确认可用性。
宝塔部署music测试
部署过程中,我发现api服务器还是常规的node app.js才能运行,但前端播放界面是可以用nginx部署静态的方式进行部署,询问老师后确认了实质上vue架构npm builder后就成了静态文件了,届时可以在workbench上像部署静态文件一样进行部署即可。
我就先部署前端吧。
部署后播放器首页报:/top/list 接口提示 Requset failed with status code 500
在Vue-mmPlayer源文内:

src/api/index.js

排行榜详情的idx改成id,再重新编译。
不用改了,作者已经修复了

学习git

最开始我是从GitHub上git clone,然后用rm -rf *mv * .[^.]* ../来部署最开始的项目的,只不过这样的话还是不会推到附送的git上,最开始cloudide还是全英文的,阿里官方的文档也写的很简陋。
因此我就去百度搜了下别的云厂商的文档,找到华为云的详细操作教程文档,参考那个文档学会了阿里云的cloudide的使用步骤(果然相同)
然后我用Sourcetree连接项目的git仓库,将文件保存到本地,再将GitHub的内容下载到本地,覆盖掉项目git文件,然后推到git上,借此来将项目转移到云开发平台的代码仓库中,然后在cloudide内使用同步按钮,将代码仓库的东西拉到cloudide内。
后来我创建项目后不会马上打开cloudide,而是先传到云开发平台的仓库,这样第一次打开cloudide后就不需要手动同步了。

Vue-mmPlayer

作为前端部署的时候我一开始没什么头绪,傻傻的把文件一股脑上传上去,然后部署,以期待能自动化完成,可惜不行。╮(╯▽╰)╭

但在我自己的服务器上部署的时候发现可以把dist文件夹内的文件当作纯静态文件来对待,虽然用文本方式打开后里面部署常规的格式。但还能提取一些关键信息。
因此我直接把宝塔上部署好的Vue-mmPlayer的dist文件夹内的文件按纯静态的方式弄到workbench上,使用nodejs迁移方案来部署,可以从临时域名访问,一次跑通就部署到线上环境了。去解析那修改成workbench的临时域名就行了。

NeteaseCloudMusicApi

先谷歌搜了下资料,怎么判断项目使用的架构。知道了查看package.json,里面的dependencies,里面有个组件是express,刚好是老师之前提到过的一个nodejs架构,因此我们可以使用workbench的express迁移方案来部署。

看迁移方案readme内的文件,有两个关键点。
1.

## 添加依赖
- 在 package.json 中,添加开发依赖
{
  "name": "xxxxxx",
  "version": "xxxx",
  .....
  "devDependencies": {
    "@midwayjs/faas-cli": "*"
  }
}

这里面的含义是要安装@midwayjs/faas-cli组件,也就是说在之前项目的基础上要加入@midwayjs/faas-cli,而不是直接使用原来的项目的package.json文件,说起来cloudide的package.json不能被覆盖,我是先手动删除后再上传的,作为bug提交给老师了,不知道啥时候修复。
2.

## 部署
- 结束调试模式
- 在 app.js 中注释对 3000 端口的监听
- 点击 CloudIDE 侧边栏的「WB」部署插件,选择要部署的环境,点击「部署」,等待部署完成即可
- 默认打包 app/ 和 config/ 两个目录,如果你的应用需要将其他目录也一起打包,需要在 f.yml 中添加如下配置,比如 util 目录也要打包:
package:
  include:
    - util

原来的readme这里package后面没带冒号,我在这里给他加上了。
还有这里是选择打包的文件,如果对项目不熟悉的话,建议打包所有的文件。
就像我的:

package:
  include:
    - util
    - module
    - docs
    - module_example
    - plugins
    - public
    - static
    - test

我也不知道哪些需要,只不过都打包只要不超过50M也没问题。

又因为原作者在app.js内指定了端口,翻看了一下直接注释掉试试可以

// const port = process.env.PORT || 3000
// const host = process.env.HOST || ''

// app.server = app.listen(port, host, () => {
//   console.log(`server running @ http://${host ? host : 'localhost'}:${port}`)
// })

监听貌似是监听所有来源,就不用管了。

部署上线后,发现api失效,是因为Vue-mmPlayer在前端主动加了:3000,手动修改下前端文件就行了。也就一个js文件,不用重新编译。看来是用js结合html文件生成一个网页,然后点击的时候是直接在前端对api提出请求。

发卡验证站

参考老师的最后一课,我改造了下,注释掉了注册功能,因为我不确定能保证注册的功能完整性,主要还是没系统学习nodejs,因此参考盗版电影、小说网站做了一个授权机制,使用keyid+密钥方式进行授权,届时使用发卡站卖id+密钥。先完成任务,其他的以后再说

优化

结合起来

首先部署的三个站分别是key站和播放站这两个独立的系统,因此我需要将他们结合起来。
我知道有传统的跳转的nodejs代码,但我没把喔一下子部署,因此就使用了referer进行跳转,也有一定的安全性(毕竟普通用户也不懂这个)。
我的想法在最早是来源这篇文章。

https://blog.wolfogre.com/posts/anti-hotlinking-without-referer/

1.key ⋙ music
先去key站的源码那,改造了下登录成功的提示那部分,最开始使用 window.location.href,但在火狐下运行不正常,因此我替换成window.location.assign以兼容火绒

.then(resp => {
  if (resp.success === true) {
    alert(`登录成功,即将进入播放页面。ID:${resp.user.name}`)
    window.location.href = "http://music.coldark.cn"
  } else {
    alert(`登录失败,提示信息:${resp.message}`)
  }
})

2.music ⋙ key
最好的办法就是在music源码里加一个referer识别,但我不会,也想尽可能减少源码的改动。其次就在cdn厂商那添加,但我用百度云cdn居然不支持referer来源白名单,腾讯云cdn支持但没免费的waf。。。。刚好我需要加层反代,因此就用nginx处理吧,先能上线再说。
还有就是播放器页面部署的时候是当作静态部署的,感觉是没法判断referer的(至少没思路)

美化

替换了下图片,和文字,将他们结合一下,这直接在源码搜索替换就行了。

防御

阿里的api网关的功能用了下,缺功能,我还是在高防服务器反代后进行限频+防cc吧。渗透倒不用担心。
在dns解析那指定了国外解析ip为127.0.0.1,防御那行发卡站的ddos,个人ddos的话用百度云cdn廉价版的waf够了。
再加上即使百度云穿透后,甲骨文的vps自带高防,因此不用怕ddos了。

百度统计

播放站自带百度统计代码,修改下js后面的数字就行了。

源码

以下是我项目的源码,大家可以直接把全部文件放到workbench的cloudide内,直接绑定自己的域名就行了。

感谢

感谢阿里云的黄贤良、风驰等各位给我们上课、解答问题的大佬们,还有钉钉群的小伙伴们,还有reldens-skeleton、Vue-mmPlayer、NeteaseCloudMusicApi的作者、discord及QQ群的大佬们。


参考:
一种新的可应对空白 referer 的防盗链策略
Sweet Alert弹窗点击确定后执行页面跳转等操作
万物皆可 Serverless 之我的 Serverless 之路

最后修改:2020 年 08 月 19 日
如果觉得我的文章对你有用,请随意赞赏