将博客迁移到又拍云

2023-01-31
次阅读
8 分钟阅读时长

考虑到使用一台独立的服务器来部署静态博客多少有点浪费,所以决定将博客迁移到又拍云上,一是可以节省服务器成本;二是可以利用又拍云多节点 CDN 提升博客的访问速度。之前为了将博客图片托管到又拍云上,参加了又拍云的联盟活动,每个月可以免费获得 10GB 存储空间 + 15GB CDN 流量,对于我这个小博客是完全够用的。

编写部署脚本

首先,为了能够通过 Github Actions 将博客文件自动同步到又拍云上,需要写一个脚本来实现上传文件的逻辑。

在此之前,我已经写过一个这样的脚本,用来将博客图片同步到又拍云上。这次用 Go 重写了这个脚本,旧版本的脚本执行需要四十多秒,而新的脚本执行只需要三秒钟。

主要是因为使用了 Go 语言自带的协程和 Channel,并将上传文件的逻辑放在协程中,使得主流程不会被上传文件的动作阻塞,实现并发上传文件,从而达到提升执行速度的目的。

相关代码已经上传到 GitHub:https://github.com/her-cat/upyun-deployer,感兴趣的话可以看一下。

脚本的逻辑分为两部分:上传文件、清理已删除的文件和空目录。

上传文件

上传文件时,先检查文件在又拍云存储库中是否已经存在,如果不存在则直接上传;存在的话就检查文件的 md5 值是否一致,一致则说明该文件没有被修改,不需要处理该文件,否则重新上传该文件。

清理已删除的文件和目录

当本地删除了某个文件后,又拍云的存储库要同步删除该文件;当目录中没有任何文件时,需要删除该目录。

为了实现这一点,在上传文件之前,我们需要从又拍云拿到所有的文件及目录的相对路径,并保存到 files 和 dirs 数组中。 每次上传本地文件时,先将本地文件的相对路径从 files 数组中删除,并将该路径对应的多级目录从 dirs 数组中删除。

当所有的本地文件都上传完毕后,files 和 dirs 数组中剩余的文件和目录就是我们要清理的内容,直接调用又拍云删除接口即可。

要注意的是,删除目录时,需要从最深层的目录开始删除,否则就会由于目录中存在子目录导致删除失败,即使子目录是空的。

比如有 /a/b/a/a/b/c 三个目录,一定要按照 /a/b/c/a/b/a 的顺序依次删除。

设置边缘规则

将所有文件都上传到又拍云之后,我们就可以直接在浏览器中访问博客了。但是,有时候需要配置一些重定向规则,比如旧文章的 URL 重定向、资源不存在时自动跳转到 404 页面等等。在使用服务器部署的时候,都是通过编写 Nginx 配置来实现这些规则,而在又拍云中则是通过设置「边缘规则」。

边缘规则支持两种设置方式,第一种是通用模式,这种模式上手简单,不需要了解边缘规则的语法规则;第二种是编程模式,比前一种模式更加灵活、强大,前提是你要熟悉它的语法规则。

下面是我配置的一些边缘规则。

统一域名

第一个规则是为了统一域名,我的博客域名是 her-cat.com,而有的人则喜欢使用 www.her-cat.com 进行访问。为了兼容这两种方式,我将 her-cat.com 和 www.her-cat.com 都解析到了又拍云上,然后使用边缘规则对请求的域名进行检测,当域名等于 www.her-cat.com 时,就使用 301 跳转到 her-cat.com。

这个规则我使用的是编程模式,规则内容如下:

$WHEN($EQ($_HOST,www.her-cat.com))$REDIRECT(https://her-cat.com$_URI,301)

语法说明:

  • $_HOST:请求的域名
  • $EQ:判断两个值是否相等,返回 true 和 false
  • $WHEN:条件判断语句,当括号中为 true 时,执行后面的语句
  • $REDIRECT:执行重定向,第一个地址重定向的地址,第二个是状态码

旧文章重定向

在国庆的时候,我将静态博客的构建工具从 hexo 换成了 hugo,带来的问题就是博客中所有文章的地址都发生了变化。原来的地址是 https://her-cat.com/年/月/日/slug.html,新的地址是 https://her-cat.com/post/年/月/日/slug/。可以看到,域名后面多了 post 并且删除了 .html 文件后缀,变成了 / 结尾。由于一些文章已经被收录或者其它站点所引用,如果不进行重定向就会导致无法使用原来的地址访问。

这里使用的也是编程模式,与上一个规则相比多了一个步骤,需要先 URL 中提取出年、月、日、slug,然后再进行 301 重定向。

URL 字符串提取:

^/(\d+)/(\d+)/(\d+)/([\w-]+).html$

规则内容:

$REDIRECT(https://her-cat.com/posts/$1/$2/$3/$4/,301)

在 URI 结尾追加 /

在 hugo 中,强制要求所有页面的 URI 都必须以 / 结尾,否则无法找到对应的页面。

解决方法是当检测到 URI 不是以 / 结尾时就自动追加 / 并 301 重定向,当然还有一些特殊情况需要处理,比如请求的是文件时不做处理。

这里使用的是通用模式。

条件判断:

  • 请求 URI 正则不匹配(不区分大小写)^/.*/$
  • 并且 请求 URI 正则不匹配(不区分大小写)(jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|txt|html|xml|js|css|woff2)$
  • 并且 请求 URI 正则不匹配(不区分大小写) /$
  • 并且 请求 URI 不等于 /

满足以上条件时,执行功能:

  • 执行 边缘重定向 动作,响应 301 状态码,重定向地址为 https://her-cat.com$_URI/

404 页面

最后一个规则是当请求的页面不存在时,自动重定向到 404 页面。执行重定向动作之前,需要先判断请求的文件类型,如果是资源文件则不处理,只重定向对页面的请求。

这里使用的是通用模式。

条件判断:

  • 请求 URI 正则不匹配(不区分大小写)(jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|txt|html|xml|js|css|woff2)$

满足以上条件时,执行功能:

  • 执行 自定义错误页面 动作,响应 404 状态码,跳转地址为 https://her-cat.com/404.html

到这里边缘规则就全部设置完了,在使用正则表达式的时候需要注意,边缘规则并不支持标准的正则表达式。

比如匹配以 .html 结尾的 URI 时,正常使用 \.html$ 就可以了,但是又拍云不支持 \. 这种写法,并且没有任何错误提示,需要不断地编辑、保存规则然后进行调试才能找到问题。

其它设置

下面是又拍云提供的一些功能,可以提升博客的体验以及访问速度。

  • 浏览器缓存:启用配置图片、字体、样式等文件的缓存。
  • 智能压缩:开启 Gzip 和 Brotli 压缩,减少传输内容大小。
  • 页面压缩:自动去除页面文件中非必要的字符(空白、注释等),加快传输速度。
  • TLS 1.3 加密协议:一种全新的加密协议,它既能提高终端用户的访问速度,又能增强安全性。
  • HTTP/2 传输协议:支持包括采用二进制格式传输数据、对消息头采用 HPACK 进行压缩传输、多路复用等特性。
  • WebP 自适应:智能判断浏览器是否支持 WebP,来决定返回 WebP 格式图片还是原图,从而减少网络传输消耗。
  • HTTPS:可以使用 Let’s Encrypt 免费的证书,并且支持自动续费。

优化博客访问速度

使用 PageSpeed Insights 工具对博客进行分析后,发现博客有很多可以优化的地方,比如字体文件、图片等资源的加载。下面是优化前后的评分对比。

优化前:

优化后:

优化字体加载

Eureka 主题默认使用 Google fonts 来加载所需的字体文件:

https://fonts.googleapis.com/css2?family=Lora:wght@400;600;700&family=Noto+Serif+SC:wght@400;600;700&display=swap

可以看到,主题使用了两种字体:Lora 和 Noto Serif SC,后面的 400;600;700 表示需要三种粗细值,display=swap 表示在 Google fonts 加载完成之前,先用系统自带的字体完成页面渲染,字体加载完成之后再用相应的字体进行渲染,避免加载字体时白屏闪烁的问题。

下面是该请求返回的 CSS 样式(部分):

/* cyrillic-ext */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/lora/v26/0QIvMX1D_JOuMwf7I_FMl_GW8g.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/lora/v26/0QIvMX1D_JOuMw77I_FMl_GW8g.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

像这样的 @font-face 定义一共有 306 个,也就是说最坏的情况需要发起 306 个请求才能完成页面上所有字体的渲染,为什么要分成这么多字体文件呢?

目的是按需加载字体文件,提高字体的加载速度。在 unicode-range 中定义了字体文件包含的字符编码范围,当页面上需要用到相应的字符时,浏览器就会请求 src 中的地址加载字体文件进行渲染。

分析网络请求后发现,首次打开博客大概需要发起 30 多个请求来获取字体文件,由于 Google fonts 的服务器在国外,所以即使开启了浏览器缓存,首次访问还是需要花费较长的时间。为了解决这个问题,我将字体文件上传到了又拍云,通过又拍云的 CDN 节点提升字体的加载速度。

操作步骤:

  • 将 CSS 文件中所有的字体按照路径下载到本地。
  • 将 CSS 文件中所有的 fonts.gstatic.com 替换成又拍云的访问域名。
  • 将 CSS 文件和字体文件按照路径上传到又拍云。

打开 https://file.her-cat.com/fonts/fonts-family.css 可以看到最终效果。

除此之外,还需要在又拍云中为字体文件配置浏览器缓存,避免每次都从又拍云加载字体文件。

优化图片加载

关于图片的优化主要是首页的头像和底部的又拍云 Logo。

头像的问题在于没有给图片设置宽度和高度,如果图片在页面渲染完成之后才加载出来,会导致图片附近的元素会发生位移,会感觉页面好像抖了一下。

又拍云 Logo 问题在于加载的图片很大,但是实际上又不需要这么大的图片,可以使用又拍云的图片处理对图片进行压缩,下面是压缩前后对比。

压缩前:

压缩后:

优化资源文件加载

在查看分析报告的时候,发现博客中所有的页面都加载了代码高亮和评论模块的 JS 以及 CSS 文件,但实际上除了详情页面以外,其它页面都不需要代码高亮以及评论功能。为了解决这个问题,我们只需要在 baseof.html 页面中判断一下的页面类型,只有详情页面才加载代码高亮和评论模块相关资源。

首先将主题下的 baseof.html 文件拷贝到博客的 layouts/_default/ 目录下,对 baseof.html 文件进行重写,然后将文件中代码高亮和评论相关的代码删除,替换成以下内容:

{{ $currentPage := . }}
{{/* 判断是否为详情页面 */}}
{{ if eq $currentPage.Kind "page" }}
{{/* 引入评论相关资源 */}}
<link rel="stylesheet" href="https://unpkg.com/gitalk@1.8.0/dist/gitalk.css">
<script id="gitalk_js" async src="https://unpkg.com/gitalk@1.8.0/dist/gitalk.min.js"></script>
{{/* 引入代码高亮相关资源 */}}
{{- $assets := .Site.Data.assets }}
{{- if eq .Site.Params.highlight.handler "chroma" }}
{{- $highlightCSS := resources.Get "css/syntax.css" | minify | fingerprint "sha384" }}
<link rel="stylesheet" href="{{ $highlightCSS.Permalink }}" media="print" onload="this.media='all';this.onload=null">
{{- else if eq .Site.Params.highlight.handler "highlightjs" }}
{{- $highlightjsStyle := .Site.Params.highlight.highlightjs.style | default "base16/solarized-light" }}
<link rel="stylesheet" href="{{ printf $assets.highlightjs.css.url $assets.highlightjs.version $highlightjsStyle }}"
      {{ with $assets.highlightjs.css.sri }} integrity="{{ . }}" {{ end }} media="print"
      onload="this.media='all';this.onload=null" crossorigin>
<script defer src="{{ printf $assets.highlightjs.js.url $assets.highlightjs.version }}"
        {{ with $assets.highlightjs.js.sri }} integrity="{{ . }}" {{ end }} crossorigin></script>
{{- range .Site.Params.highlight.highlightjs.languages }}
<script defer src="{{ printf $assets.highlightjs.languages.url $assets.highlightjs.version . }}"
        {{ with $assets.highlightjs.languages.sri }} integrity="{{ . }}" {{ end }} crossorigin></script>
{{- end }}
{{- $highlightjsCSS := resources.Get "css/highlightjs.css" | minify | fingerprint "sha384" }}
<link rel="stylesheet" href="{{ $highlightjsCSS.Permalink }}" media="print" onload="this.media='all';this.onload=null">
{{- end }}
{{ end }}

总结

这篇文章介绍了我是如何将博客迁移到又拍云并实现自动化更新博客的,顺便介绍了如何使用边缘规则来实现对请求的处理,最后提到了我对博客的一些优化,虽然优化的手段都比较常规,但实际效果还是很不错的。

最后,祝大家兔年大吉!

本文作者:她和她的猫
本文地址https://her-cat.com/posts/2023/01/31/blog-migration-to-upyun/
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!