多折点
一个专注各类有用知识分享的网站

零成本搭建简单图床Backblaze+CloudFlare

Backblaze的B2对象存储对和国内阿里云的OSS、腾讯云的COS在功能上差不多。但是对比国内厂商优缺点也非常明显。

  B2 国内厂商
容量 10G免费 收费
价格 上行免费,下行每天1G免费 收费
CDN 配合CF的CDN,流量全免 收费
速度 位于国外,速度慢 位于国内,速度快

这次主要就是Cloudflare的流量联盟计划来实现0成本搭建一个自己的图片存储空间。

流量联盟是CF推出的,为了节省云服务商之间的流量消耗的计划。有很多国际大厂都加入了这个联盟,当然包括今天说的Backblaze。

通过CF的CDN加速B2使所有流量全免费,加上B2的10G免费容量,实现0成本的图床

这篇文章的图片均托管在B2+CF的网络下,各位可以作为网络和稳定性参考。

注册B2

点击这里注册帐号。注册过程非常简单,只需要填写邮箱和密码。注册完后登陆帐号,在 我的设置 里验证一下邮箱

B2验证邮箱 

创建容器

验证完邮箱后创建一个  ,自己设置一下名称。然后通过网页上传一张图片到  内。点击刚才上传的图片,在出现的窗口里找到 友好的URL ,保存好前面这段网址https://xxx.backblazeb2.com

获得网址 

CloudFlare解析

来到CF面板,添加一条CNAME记录,记得打开云朵

cf解析 

增加CloudFlare规则

这时候已经可以通过自己的域名来访问刚才上传的图片了,但是图片连接里会包含自己的  名字,为了安全起见,可以通过CF规则将它隐藏。

concat("/file/lms-example", http.request.uri.path)

cf重写规则 

有了重写规则,现在可以直接通过 https://域名/文件名 来访问自己的文件了。

然后在CF的页面规则里设置一下缓存时间。既然是做,一般不会去修改。所以这边缓存时间改为7天。

cf缓存 虽然现在已经可以访问图床文件,但是图床 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。设置非常简单,就不多做介绍了。