封面图片 来源
这篇博客用于测试基于本博客专用的图床系统,该图床基于 Cloudflare Workers 和 Cloudflare R2 存储桶搭建。
以下查看使用 Markdown 直接插入图片的显示效果。
理论上来说,该图片仅在本博客下可以正常显示,使用新标签页打开此图片的来源地址时会禁止访问。
注意,从本博客点击图片来源地址仍可以访问,例如点击博客开头的封面图片 来源 或在图片上右击选择新标签页打开,此时仍可以访问图片。如果直接新建空白标签页并粘贴图片地址,访问将被禁止。 搭建方法来源于 CloudflareR2快速开始使用(白嫖)指南 和 Cloudflare R2对象存储当图床测试 。
基于 Cloudflare 的搭建方法
首先创建 R2 存储桶。
然后创建 Cloudflare Workers 项目,代码如下:
addEventListener("fetch", event => { event.respondWith(handleRequest(event.request))})
async function handleRequest(request) { const url = new URL(request.url) const objectName = url.pathname.slice(1) // /path/to/file => path/to/file
console.log(`${request.method} object ${objectName || '(root)'}: ${request.url}`)
// 只允许 GET / HEAD if (request.method !== 'GET' && request.method !== 'HEAD') { return new Response('Method Not Allowed', { status: 405 }) }
// 不提供根路径列表,直接返回 404,避免暴露 bucket 结构 if (!objectName) { return new Response('Not Found', { status: 404 }) }
// ====== GET:读取对象内容 ====== if (request.method === 'GET') { const object = await R2.get(objectName, { // 让 R2 自己解析 Range、条件请求等头 range: request.headers, onlyIf: request.headers, })
if (object === null) { return objectNotFound(objectName) }
const headers = new Headers() // 将 R2 中保存的 HTTP 元数据写入响应(Content-Type、Cache-Control 等) object.writeHttpMetadata(headers) headers.set('etag', object.httpEtag)
// 如果客户端发送了 Range 头,则声明支持分块 if (request.headers.has('range')) { headers.set('accept-ranges', 'bytes') }
// object.body 为空表示满足条件请求(如 If-None-Match),返回 304 const status = object.body ? (request.headers.has('range') ? 206 : 200) : 304
return new Response(object.body, { status, headers }) }
// ====== HEAD:只返回元信息,不返回 body ====== if (request.method === 'HEAD') { const object = await R2.head(objectName)
if (object === null) { return objectNotFound(objectName) }
const headers = new Headers() object.writeHttpMetadata(headers) headers.set('etag', object.httpEtag)
return new Response(null, { status: 200, headers }) }}
// 404 响应function objectNotFound(objectName) { return new Response( `<html><body>R2 object "<b>${objectName}</b>" not found</body></html>`, { status: 404, headers: { 'content-type': 'text/html; charset=UTF-8' } } )}回到新建的 Workers 项目首页,来到 设置 - 变量 - R2 存储桶绑定 ,添加绑定 后变量名称填写 R2 ,R2 存储桶选择刚才创建的图床存储桶,然后 部署 。
使用方法
来到 Cloudflare R2 存储桶首页,选择图床所在的存储桶,直接上传图片即可。需要访问图片时,如果你的图床 Workers 项目自定义域为 img.example.com ,图片文件名为 img.png ,那么访问地址为 https://img.example.com/img.png 。
安全性措施
Cloudflare 提供的 R2 存储桶的免费容量为 10 GB 每月,免费的 A 类操作次数为 100 万次每月,免费的 B 类操作次数为 1000 万次每月。正常自己使用是用不完的。被刷了那就乖乖掏钱吧
配置 Cloudflare 缓存
新方法
推荐使用新方法,新方法不会占用免费的3个页面规则,两种方法选一种配置即可。
来到图床所在 域名 - 缓存 - Cache Rules 下 创建规则 。
规则名称 随便填。
当传入请求匹配时…
| 字段 | 运算符 | 值 |
|---|---|---|
| 主机名 | 等于 | img.example.com |
img.example.com即为图床的地址。
则…
缓存资格:符合缓存条件。
添加 边缘 TTL:忽略缓存控制标头,使用此 TTL => 6 个月。
添加 浏览器 TTL:忽略缓存控制标头,使用此 TTL => 1 个月。
然后 部署 。
传统方法
不推荐,此方法会占用免费的3个页面规则。
来到图床所在 域名 - 规则 - 页面规则 下 创建页面规则 。
URL 填 img.example.com/*
img.example.com即为图床的地址,/*是指该地址下所有内容。
点击 + 添加设置 。
| 选取设置 | 选择 |
|---|---|
缓存级别 | 缓存所有内容 |
浏览器缓存 TTL | 1天 |
边缘缓存 TTL | 1个月 |
然后 保存和部署页面规则 。
现在访问图片时,访问的都是 Cloudflare CDN 服务器上的内容,不会占用 R2 存储桶的操作次数。
浏览器缓存 TTL 是指浏览器第一次访问这个地址后,就会把地址对应的文件缓存到本地。
接下来在 TTL 时间内,浏览器再次访问这个地址时,都是直接调用本地缓存的文件。
边缘缓存 TTL 是指你第一次访问这个地址后,为你提供这个地址资源的 CDN 节点会缓存这个地址对应的文件。
接下来在 TTL 时间内,你再次通过这个节点访问这个地址时,这个节点会直接调用缓存的文件。
TTL 就是缓存有效期,过期后就要重新缓存。
防盗链
防盗链就是防止别的网站直接抓取我的网站,然后显示在它的网站上,就是防止我的图床承担其他网站的访问流量然后免费次数被刷爆了掏钱。
来到图床所在 域名 - 安全性 - WAF 下 创建规则 。
规则名称 随便填。
| 字段 | 运算符 | 值 |
|---|---|---|
| 引用方 | 不包含 | blog.example.com |
| And | ||
| 主机名 | 等于 | img.example.com |
其中
blog.example.com即为博客地址,img.example.com即为图床地址。
然后采取措施:阻止 。
此时只有在博客
blog.example.com内访问图床img.example.com才可以成功。如果不是从博客blog.example.com内访问图床img.example.com,访问请求将被阻止。
这样对图床地址就有了一个基本的保护。