小小的改进给探索子博客带来了大大的进步

2020-07-04

摘要

本篇文章分享今日来该博客网站上发送的改进,包括:这些改进解决了哪些问题、带来了什么好处,以及,这些改进是如何做出的,还包括,这些改进主要是在哪些方面的,还有,改进后的最新架构是怎样的.

引言

现今而言,主流的博客网站搭建方案大体上可分为「静态的」(static)和「动态的」(static),大概,即,平日里我们说的「静态网站」和「动态网站」;功能上而言,这两者是没有太大差别,作者写,内容就被生成并同步,动态网站如Wordpress和Typecho通过插件提高拓展功能,静态网站如Hexo和Hugo通过JavaScript标签和第三方API提高拓展功能,动态能做到的静态也能做到,反之亦然.然而,由于具体实现也就是具体的提供给用户的操作接口不同,静态的解决方案拥有更容易实现的拓展性也就是可玩性.

静态网站生成器(Static Site Generator)实质上仅仅是将弱标记语言写成的文本(Markdown)转换为强标记语言构成的用户认为两者等价的文本(HTML),类似于编译器仅仅是将程序设计语言(Programming Language)写成的文本转换为另外一种语言构成的文本一样,这样,就使得一个静态网站好像一个程序一样它可以被构建(Build)和分发(Distribute)!Markdown相当于「源代码」而HTML则相当于「可执行文件」,版本管理自然可以沿用软件开发中的那一套解决方案——它们之中最流行的——也就是Git.

Git能够追踪一个项目中每个「被跟踪」(tracked)的文件的变化,也就是能够记录下每个文件在不同时期的变化并且能够在未来回溯和检查它们,对于文本文件来说,这样是好的,是有用的,对于源文件来说,也是好的,也是有用的,但是对于目标文件(HTML)和非文本文件(PNG, JPG, PDF, …)而已,则是不必要的,顺便说,在Hugo中,静态文件是专门约定被置于static目录中,于是我们自然而然地也就没有将static目录编入Git仓库中.但是,这样的话,假如说在某一天我需要从Git版本仓库中把博客文件夹恢复出来,会发现没有static这个目录.所以,我们需要在Git之外单独地、另外地跟踪静态文件的变化.这里,当我们提到「追踪」或者「版本管理」这方面的内容时,你可以理解为「备份」,事实上有很大概率我们是不会主动去回溯项目以往的版本的,Git一个项目仅仅是为了备份,也就是在必要时候可以使系统恢复到正确状态,Git在这里它类似「时光机」一样的存在,我们希望,对于静态文件组成的子系统,也有这样的「时光机」可以在必要时刻能够对不一致的系统做出恢复操作使系统恢复到一致状态.

旧的和新的

在以往,我们在本地撰写Markdown文档,将Markdown文档中包括的插图放入static目录,写完之后运行hugo命令构建静态网站的「可发布文件」(也就是HTML文件,位于public目录中),然后使用rsync工具将public目录同步到远端的网页服务器根目录,这就完成了一次博客内容的更新.

现在,我们仍然是在文章撰写完毕后运行hugo命令进行可发布文件的构建,文章所需要的静态文件(图片、视频等)仍然是放入static目录中,然而,此时不同的是,我们不再用rsync工具将public目录同步到远端服务器,借鉴持续集成(Continous Integration, CI)的思想,当需要做出一次更新时,我们在本地用Git创建一次新的提交

git add content
git commit -a -m "正在撰写新的文章"

随后将提交推送到远端服务器上

git push cds public

而在服务器收到推送后,会首先尝试将提交并入主干分支,成功后运行hugo进行静态网站的构建,与之前不同的是,这时我们是在服务器上运行hugo构建静态网站而不是在本地.

在这整个过程中,你也注意到了,我们根本没有提到静态文件!文章中引用到的静态文件仅仅放在本地的话,访客访问网站的时候是看不到的,尽管,在服务器上的Hugo项目文件中,没有static文件夹也能构建HTML可发布文件,但是我们还是要确保访客访问网站时访客的浏览器能够成功地请求到静态文件.面对这个静态文件的递送问题,我们前后总共提出过三个方案:

方案一,是使用rsync工具将static目录直接同步到远端网页服务器的对应目录,但是,从文件备份和版本管理这个需求来说,这并不是很好的解决方案,或者说这并没有解决静态文件的文件备份和版本管理问题,仅仅解决了递送问题.

方案二,我们看向了云存储,首先我们考虑过Dropbox,因为Dropbox有文件的版本管理功能,可以在必要时刻按需回溯到一个文件以前的版本,但是Dropbox的费用很高昂,而且免费版本的存储空间非常小(才2GiB),然后,我们决定使用Amazon S3,配合方便的Rclone工具和灵活的Gulp,我们也能实现Dropbox的文件自动同步功能,并且Amazon S3支持对象的版本回溯,价格是按使用量付费,这对于我们来说简直太好了.在此必须感谢Rclone项目和Gulp项目.具体来说,我们在Hugo项目目录下写一个gulpfile.js,主要内容就是指示gulp监视static目录下的任何变动:当static目录下有变动时,就调用rclone自动地将static目录和Amazon S3同步,这样,初步解决了文件的递送问题,而且是这是自动化的,我们不再需要每次都手动rsync了,同时,这还解决了静态文件的版本管理和文件备份问题.接下来需要解决的是静态文件的分发问题(递送——分发,递送是指把文件传到公网服务器上,分发是指把文件分发给用户),面对这个问题,我们前后又有3种不同的尝试:最开始,我们利用Amazon S3的事件机制,将Amazon S3的写事件作为Amazon Lambda(匿名云端函数)的「触发器」,即,在Amazon S3中进行一些设置使得当有文件被上传时触发一个云端函数,然后被触发的那个云端函数再向该网站的服务器发送一个HTTP请求请服务器向Amazon S3拉取最新的变化,后来我们没有实现这个方法,因为实在非常复杂.尝试解决这个文件分发问题的另外一个方法呢,就是在本地rclone正常退出后,本地直接向服务器发送一个HTTP请求请服务器像Amazon S3拉取最新变化,可是这样一来虽然没有了Amazon S3的事件配置和Amazon Lambda,却仍然至少需要在服务器上设定一个事件监听程序监听HTTP请求,或许还涉及到域名、证书、反向代理、API保护等各种方面,于是这样一种文件分发的方法我们同样放弃了.

方案三,同样地,文件的递送方法是继承方案二提出的——在本地监听static目录下的变化并且当有变化发生时自动和Amazon S3同步,我们之前想的可都是:静态文件还在本地,所以要把静态文件同步到网页服务器上,否则访客打开网页的时候就会发现静态资源加载不出来,但是为了要使访客打开网页时浏览器能加载出静态资源就必须要把静态文件同步到网页服务器上吗?事实上是根本没必要的,根本没必要将静态文件上传到网页服务器上.具体来说是这样子的:访客(浏览器)像我们的网页服务器请求静态资源,路径会是

(.*)\.(jpe?g|png|ico|webp|svg|gif|mp4|mp3|avi|mov|pdf)

例如/path/to/image1.png,我们的网页服务器发现请求路径匹配这样的正则的时候,就可以推断访客正则请求的是一个静态文件,所以不能从本地中找这个静态文件给访客,那就干脆直接反向代理Amazon S3,从Amazon S3请求相应的静态资源,并把Amazon S3返回的结果作为响应返回给客户端好了,如下是NginX配置

location ~* \.(jpe?g|png|gif|ico|svg|pdf|md|mp4)$ {
    proxy_pass https://amazons3endpoint;
}

这样一来,就完美地解决了静态文件的分发问题,静态文件只需从本地上传到Amazon S3,根本不需要再上传到我们的网页服务器,作为访客照样察觉不出这有什么异样!

前后比较

前后比较

过程的收获

为了实现上面提到过的这些,我学习了:Telegram Bot API, githooks以及使用Node.js写githooks脚本, gulp的基本概念和gulpfile.js的书写,Amazon S3的配置和使用,Amazon Lambda的配置和使用,Amazon API Gateway的配置和使用,Cloudflare Workers的功能和简单的使用方式,使用wrangler提交Cloudflare Worker代码,使用aws提交Amazon Lambda代码,将Amazon Lambda和Amazon API Gateway连接起来,Rclone的简单使用.我发现在整个过程中JavaScript是通用的.

在Telegram频道上的自动提示

在Telegram频道上的自动提示

展望及未来可能性

引入GitHub Actions和Netlify,使博客彻底摆脱对VPS的依赖,用Cloudflare Worker依据Path对请求进行分流,确保客户端所需的资源被正确的请求到,采用WebP格式的图片加快图片加载.

博客搭建bloggulpaws

从任意分布中构造任意分布

近期项目进展