Backblaze B2 + Cloudflare Worker + ShareX - Markdown写作图床解决方案

Intro

写博客肯定离不开图床,特别是Hexo这种静态博客。

通过本文方案,可以很轻松地实现 截图自动上传并生成url、使用自定义图床链接、缩短图床URL等一系列功能,十分方便Markdown写作。

介绍

Backblaze B2https://www.backblaze.com/b2

​ 类似于 AWS S3 的云端存储解决方案,Free Plan 拥有 10GB 免费存储额度。

​ 此外,根据 CF 的带宽联盟计划 ,B2 至 Cloudflare 的出口流量将不收取任何费用。

Cloudflare Workerhttps://workers.cloudflare.com/

​ Cloudflare 推出的云函数功能,我们将通过 它重写URL,得到一个较短的图床链接。同时如果你有自己的域名的话,可以将某个解析域名路由至该Worker,使用你的自定义域名来访问图片。本文我们不单单用到Worker的功能,还需要使用 CF 的 CDN 、DNS 等功能。

ShareXhttps://getsharex.com/

​ 开源的录屏&图片处理工具,我们将用它来实现截图自动上传、自动生成url等功能。当然支持自动上传的工具还有很多,这里就不一一赘述。

1. 创建 B2 Bucket (存储桶)

注册:https://www.backblaze.com/b2/sign-up.html?referrer=nopref

注意Bucket类型选择:Public,其他默认即可。

创建完成后先尝试上传一张图片,然后在左侧点击 Browse Files 栏目,查看上传的图片详情,我们需要获取到 Fridenly URL 路径以供后续 Cname使用。

记住这个 https://f004.backblazeb2.com

2. Cloudflare 配置

2.1 CNAME 解析

首先配置DNS记录,使你的自定义域名指向 B2 Friendly URL。

例如我想使用 img.web.sb 访问图床,则可以设置 CNAME(注意勾选代理状态,否则流量不会通过Cloudflare CDN) :

这时候将上述 Friendly URL 的 f004.backblazeb2.com 替换为 img.web.sb 就可以访问啦。(此时 Path 中仍然包含了 file/bucket_name/ 信息,我们可以通过下文配置Cloudflare Worker 进行重写使其缩短。)

*若此时访问出现 522 错误,请在 Cloudflare 的 SSL/TLS 栏目 将加密模式改为 Full(Strict) 模式。*

2.2 配置 Page Rule

由于图片通常不会有边动,我们可以将缓存TTL调高,节省流量。

可以参考我的规则,缓存的TTL可以自行调整:

2.3 配置 Cloudflare Worker

​ 创建一个新服务,编辑该服务为如下内容,并修改以下两项变量即可:

  • b2Domain : 自定义域名,如我的 img.web.sb
  • b2Bucket :在创建时设置的Bucket名称
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
'use strict';
const b2Domain = 'img.domain.com'; // configure this as per instructions above
const b2Bucket = 'bucket-name'; // configure this as per instructions above
const b2UrlPath = `/file/${b2Bucket}/`;
addEventListener('fetch', event => {
return event.respondWith(fileReq(event));
});

// define the file extensions we wish to add basic access control headers to
const corsFileTypes = ['png', 'jpg', 'gif', 'jpeg', 'webp'];

// backblaze returns some additional headers that are useful for debugging, but unnecessary in production. We can remove these to save some size
const removeHeaders = [
'x-bz-content-sha1',
'x-bz-file-id',
'x-bz-file-name',
'x-bz-info-src_last_modified_millis',
'X-Bz-Upload-Timestamp',
'Expires'
];
const expiration = 31536000; // override browser cache for images - 1 year

// define a function we can re-use to fix headers
const fixHeaders = function(url, status, headers){
let newHdrs = new Headers(headers);
// add basic cors headers for images
if(corsFileTypes.includes(url.pathname.split('.').pop())){
newHdrs.set('Access-Control-Allow-Origin', '*');
}
// override browser cache for files when 200
if(status === 200){
newHdrs.set('Cache-Control', "public, max-age=" + expiration);
}else{
// only cache other things for 5 minutes
newHdrs.set('Cache-Control', 'public, max-age=300');
}
// set ETag for efficient caching where possible
const ETag = newHdrs.get('x-bz-content-sha1') || newHdrs.get('x-bz-info-src_last_modified_millis') || newHdrs.get('x-bz-file-id');
if(ETag){
newHdrs.set('ETag', ETag);
}
// remove unnecessary headers
removeHeaders.forEach(header => {
newHdrs.delete(header);
});
return newHdrs;
};
async function fileReq(event){
const cache = caches.default; // Cloudflare edge caching
const url = new URL(event.request.url);
if(url.host === b2Domain && !url.pathname.startsWith(b2UrlPath)){
url.pathname = b2UrlPath + url.pathname;
}
let response = await cache.match(url); // try to find match for this request in the edge cache
if(response){
// use cache found on Cloudflare edge. Set X-Worker-Cache header for helpful debug
let newHdrs = fixHeaders(url, response.status, response.headers);
newHdrs.set('X-Worker-Cache', "true");
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHdrs
});
}
// no cache, fetch image, apply Cloudflare lossless compression
response = await fetch(url, {cf: {polish: "lossless"}});
let newHdrs = fixHeaders(url, response.status, response.headers);

if(response.status === 200){

response = new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHdrs
});
}else{
response = new Response('File not found!', { status: 404 })
}

event.waitUntil(cache.put(url, response.clone()));
return response;
}

保存并部署后,我们可以将在 触发器 - 添加路由 将自定义域名路由至该Worker

此时我们已可以通过 https://img.web.sb/share//fiel_name.png 来访问图片了。

3. ShareX 自动化

ShareX的配置就比较简单了,在 目标 - 上传目标设置 中选择配置 B2 的 APP_ID 、Key、Bucket_Name 等信息即可,并且可以勾选上使用自定义URL,复制的链接将会自动替换成我们的自定义域名

此外还可以配置 截图后的任务上传后的任务等,实现截图后自动上传、复制URL至剪贴板、删除本地图片等操作。


Backblaze B2 + Cloudflare Worker + ShareX - Markdown写作图床解决方案
http://example.com/2022/07/20/Backblaze-B2-Cloudflare-Worker-ShareX-md写作图床解决方案/
作者
Rae
发布于
2022年7月20日
许可协议