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。设置非常简单,就不多做介绍了。