前言

2019.11.23 CodeLab在国家图书馆做了个活动,接下来会陆续开展活动,随着用户的加入,为了方便大家的交流,CodeLab的编程社区正提上日程。

我们希望构建类似scratch.mit.edu的社区。所以复用了Scratch开放的前端项目:scratch-www, 并构建了与之兼容的后端(参考Scratch3.0技术分析之后端API(第0篇))。

Scratch全球社区有海量(1亿+)优秀项目, 我们希望国内用户能方便地访问它。于是为Scratch做了CDN。

本文对CDN镜像实施时遇到的问题过个笔记。

ps: 这个思路是通用的,也是做笔记的原因。

思路

使用七牛的镜像机制来做CDN。

问题笔记

静态资源

音乐加载

Scratch将它自身的静态资源放在CDN上,诸如:

  • 角色图片
  • 背景图片
  • 音乐

角色图片 和 背景图片 会一次加载所有内容,所以打开一次,便会触发所有资源的CDN镜像机制。

音乐则不然,属于lazy load,需要逐个点击/悬停才加载,这带来了一个问题: 许多资源在第一次使用时,要等待镜像的完成,十分缓慢。

思路

有许多种解决方案,我想到3种:

  1. 修改scratch静态资源的加载机制,不使用CDN,直接从自己的服务器拉取静态资源。
  2. 与第一种方法类似,将静态资源放在自己的服务器上,但使用CDN镜像它。
  3. 镜像官方静态资源,使用自动化机制逐个镜像静态资源

为了兼容Scratch和考虑后期的升级,我决定采用第三种方案.

思路很简单: 使用正则表达式找出所有资源的标识(形如5cb46ddd903fc2c9976ff881df9273c9.wav), 写一个脚本逐个请求。

动手

思路清楚之后,很容易执行。

我们在build好的代码里,寻找音乐资源的标识(形如5cb46ddd903fc2c9976ff881df9273c9.wav)。

其实音乐资源在开发源码中更好找,我之所以在build之后的代码里找,是为了长期的兼容性,md5标识可能会改变。

简单搜索一下,可以发现数据都在lib.min.js文件里。

正则表达式

使用正则表达式找到它:

ack -ho '(?<=md5:")[a-z\d]+?.wav(?=")' lib.min.js

前边这个正则表达式,有2处可能不好理解: (?<=md5:")(?=") , 在正则中叫前瞻和后顾,实际上是把目标字符串的上下文信息加入进来,我们的目标字符串(md5:"5cb46ddd903fc2c9976ff881df9273c9.wav")以md5:"开头,以"结尾.

如果你觉得这个不好读,可以使用以下更易读的版本,当然也更啰嗦些:

ack -ho 'md5:"[a-z\d]+?.wav"' lib.min.js | ack -ho '[a-z\d]+?.wav'

一共找到792项,我们将其存到文件里

ack -ho '(?<=md5:")[a-z\d]+?.wav(?=")' lib.min.js > /tmp/music_list.txt

之后使用Python来触发对这些静态资源的镜像。

Python脚本

Python脚本的职责是,构建出音乐资源镜像地址,对其访问(HTTP OPTION/GET), 镜像地址形如:https://cdn.assets.scratch.mit.edu/internalapi/asset/5cb46ddd903fc2c9976ff881df9273c9.wav/get/

cdn.assets.scratch.mit.edu替换为镜像仓库的域名。

使用循环依次将5cb46ddd903fc2c9976ff881df9273c9.wav替换为/tmp/music_list.txt中的文件标识即可。

之后使用aiohttp client去并发请求这些资源,

当然你也可以使用任何自己喜欢的语言和http库,httpie和curl都很方便。注意设置超时时间,镜像可能需要时间,我们不必拿到请求结果,只需触发请求即可。

至此,完成上述工作。