[中文] My Experience of Picture Bed Migration

记一次图床迁移过程

起因嘛,就是这条短信:

【七牛云服务】尊敬的七牛云CDN用户,您的账号 **@**.com 下 article-assets.lynan.cn 等 3 个域名绑定的证书即将过期,为保证您的服务正常使用,请您尽快更换证书。详见邮件内容。您可登录「消息设置/产品消息/CDN 相关通知」关闭短信通知。如证书已弃用请忽略。

收到七牛的短信说明我的免费证书一年期又到了,需要重新申请、上传 SSL 证书。正好我最近因为迁移了博客到 CloudFlare,体验不错,干脆把图床也迁移了。

总得来说,迁移的好处有:

  1. 表钱
    (免费套餐包含 10GB 以内的资源,目前来说我肯定用不到限额,因为我的资源在上传前都手动压缩过,当然了如果真到不够用的时候它超出额度也非常便宜)
  2. 全球CDN
  3. 无需自行配置 SSL 证书
    继续用七牛的话,一年配置一次我都有点懒😅

收集原图床资源

鉴于当时为我的博客单独建了一个 Bucket 并且配置了单独的域名,所以找起来很容易。跑个脚本即可:

我的博客是 Hexo 生成的,原始文件都在 source 文件夹内。

getlinks.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
const { resolve } = require("path");
const { readFileSync, writeFileSync, promises } = require("fs");
const { readdir } = promises;

const directory = "source";

async function getFiles(dir) {
const dirents = await readdir(dir, { withFileTypes: true });
const files = await Promise.all(
dirents.map((dirent) => {
const res = resolve(dir, dirent.name);
return dirent.isDirectory() ? getFiles(res) : res;
})
);
return Array.prototype.concat(...files);
}

const getLinks = () => {
const res = {};

const checkContent = (files) => {
files.forEach(filePath=>{
const fileContent = readFileSync(filePath, "utf8");
const matchRes = fileContent.match(
/https:\/\/article-assets.lynan.cn[^"'()>\s]+/gi
);
if (matchRes && matchRes.length) {
matchRes.forEach(link => {
let linkText = link;
if (linkText.includes("?")) {
linkText = linkText.split("?")[0];
}
if (!res[linkText]) {
res[linkText] = 1;
}
})
}
})
};

getFiles(directory).then((filePath) => {
const files = filePath.filter((item) => !item.endsWith(".DS_Store"));
checkContent(files);
const links = Object.keys(res).join("\n");
writeFileSync("qiniuLinks.txt", links);
});
};

getLinks();

下载资源到本地

震惊了属于,七牛的 Web 端后台只能一个一个下载,批量下载其实是打开 n 个标签页,有点原始。
七牛有 SDK ,但是我作为一个切图脚本仔,还是再写一个脚本吧。。

这里的脚本的目的是为了保留原始文件的目录层级,这样的话当我上传完毕以后,只需将原来的资源 URL 更换为最新的域名即可。(或者直接把原来的 Bucket 的域名解析到新图床 Bucket)。

downloadfiles.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const axios = require("axios");
const fs = require("fs");
const _ = require("lodash");

const files = fs.readFileSync("files.txt", "utf-8").split("\n");
const directory = "files";

const domain = "https://article-assets.lynan.cn/";

let errorFiles = ''

const downloadFile = async (filePath) => {
try {
let paths = _.compact(filePath.replace(domain, "").split("/"));
paths.length = paths.length - 1;
console.log(paths);
if (!fs.existsSync(`${directory}/${paths.join("/")}`)) {
fs.mkdirSync(`${directory}/${paths.join("/")}`, { recursive: true });
}
const file = await axios.get(filePath, { responseType: "stream" });
file.data.pipe(
fs.createWriteStream(`${directory}/${filePath.replace(domain, "")}`)
);
} catch (error) {
console.log(filePath);
errorFiles += filePath
return true;
}
};

const task = async () => {
for (let i = 0; i <= files.length; i++) {
await downloadFile(files[i]);
}
if(errorFiles){
fs.writeFileSync('errorFiles.txt', errorFiles)
}
};

task();

上传到 CloudFlare R2

没有 Bucket 的新建一个 Bucket 先。

把下载好的文件拖进去上传。

替换原链接域名

我直接用 VS Code 的“查找和替换” 换好了。

打开检查一下,OK,丝滑。迁移以后只要我的域名还在,我的博客和 CloudFlare 共存亡😄

为什么不用第三方图床

其实我用了,还付费了。主要还是怕不知道什么时候突然就跑路了,不如大公司靠谱。

有点觉得不靠谱是因为我用的那个图床,似乎也是迁移了好几次(现在访问原始链接会有多个 302 重定向,虽然不影响访问,但是变慢的体感是挺明显的),在使用期间我也遇到过几次间歇性不可用,所以稳定性这一块也是有点担忧的。

R2 缓存头设置

R2 添加自定义域名以后,默认的配置是:Cache-Control: public, max-age=0, must-revalidate
对于我来说,我的当前 R2 存储桶都是用于存储不会改变的文件(图片、视频等),如果需要改变我会重新上传使用新的 URL。
因此我希望将 max-age 修改到一个月的时间。

进入 CloudFlare 域名后台: /rules/transform-rules/modify-response-header

添加一个规则,为此存储桶的域名添加响应头:

1
2
3
4
5
6
7
8
9
10
11
12
If...
When incoming requests match…

Custom filter expression

When incoming requests match…

Hostname equals r2-assets.lynan.cn

Then...

Add Cache-Control = max-age=43200000

PS. 这篇文章本来没想写,不过想想从业几年,还是挺经常写脚本的,分享一下也很有意思。

[中文] My Experience of Picture Bed Migration

https://thelynan.com/asset-links-migration/

作者

Lynan

发布于

2024-01-01

许可协议

评论