Backblaze的B2对象存储对和国内阿里云的OSS、腾讯云的COS在功能上差不多。但是对比国内厂商优缺点也非常明显。
| B2 | 国内厂商 | |
|---|---|---|
| 容量 | 10G免费 | 收费 |
| 价格 | 上行免费,下行每天1G免费 | 收费 |
| CDN | 配合CF的CDN,流量全免 | 收费 |
| 速度 | 位于国外,速度慢 | 位于国内,速度快 |
这次主要就是Cloudflare的流量联盟计划来实现0成本搭建一个自己的图片存储空间。
流量联盟是CF推出的,为了节省云服务商之间的流量消耗的计划。有很多国际大厂都加入了这个联盟,当然包括今天说的Backblaze。
通过CF的CDN加速B2使所有流量全免费,加上B2的10G免费容量,实现0成本的图床。
这篇文章的图片均托管在B2+CF的网络下,各位可以作为网络和稳定性参考。注册B2
点击这里注册帐号。注册过程非常简单,只需要填写邮箱和密码。注册完后登陆帐号,在 我的设置 里验证一下邮箱
创建容器
验证完邮箱后创建一个 桶 ,自己设置一下名称。然后通过网页上传一张图片到 桶 内。点击刚才上传的图片,在出现的窗口里找到 友好的URL ,保存好前面这段网址https://xxx.backblazeb2.com
CloudFlare解析
来到CF面板,添加一条CNAME记录,记得打开云朵
增加CloudFlare规则
这时候已经可以通过自己的域名来访问刚才上传的图片了,但是图片连接里会包含自己的 桶 名字,为了安全起见,可以通过CF规则将它隐藏。
concat("/file/lms-example", http.request.uri.path)
有了重写规则,现在可以直接通过 https://域名/文件名 来访问自己的文件了。
然后在CF的页面规则里设置一下缓存时间。既然是做图床,一般不会去修改。所以这边缓存时间改为7天。
虽然现在已经可以访问图床文件,但是图床 URL 中有一些敏感信息会暴露存储桶的名称,导致源文件有被攻击刷流的风险,所以需要配置路由以隐藏敏感信息。
注:方法不唯一,这里通过 cloudflare workers 修改路由。
cloudflare worker 的创建不再赘述,网上有很多教程。
workers 代码:
'use strict';
const b2Domain = '你的域名'; // configure this as per instructions above
const b2Bucket = '存储桶名称'; // configure this as per instructions above
const b2UrlPath = <code>/file/${b2Bucket}/</code>;
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;
}
上传图片
图片上传可以直接在Backblaze的网页上上传。Windows的话推荐ShareX,它支持很多容器,其中也包括B2。设置非常简单,就不多做介绍了。
多折点


