且听风吟

使用Cloudflare Workers + R2 实现相册功能

· 分享
最近在研究如何使用Cloudflare Workers和R2来实现一个简单的相册功能。通过结合这两项技术,我们可以创建一个高效且易于维护的在线相册系统。以下是我实现这一功能的步骤和代码示例。 ## 准备工作 1. **注册Cloudflare账号**:如果还没有Cloudflare账号,需要先注册一个。 2. **创建R2存储桶**:在Cloudflare的仪表盘中创建一个R2存储桶,用于存储相册图片。 3. **设置Workers**:在Cloudflare的Workers部分创建一个新的Worker,用于处理图片展示。 4. **设置KV命名空间**:如果需要存储图片的元数据,可以创建一个KV命名空间。 ## 代码实现 以下是一个简单的Cloudflare Worker代码示例,用于从R2存储桶中获取图片并展示在网页上。 ```javascript export default { async fetch(request, env, ctx) { const url = new URL(request.url) // 相册主页 if (url.pathname === '/') { return await generateAlbumPage(env, ctx) } // 搜索接口 if (url.pathname === '/search') { const query = url.searchParams.get('q') || '' return await searchImages(env, query, ctx) } // 图片代理(解决跨域问题) if (url.pathname.startsWith('/image/')) { const key = decodeURIComponent(url.pathname.slice(7)) return await serveImage(env, key) } return new Response('Not Found', { status: 404 }) } } // 生成相册页面 async function generateAlbumPage(env, ctx) { const images = await listAllImages(env, ctx) const html = ` My Photo Album

My Photo Album

${images.map((img, index) => `
${img.key}
${img.key}
Size: ${formatBytes(img.size)} | Uploaded: ${new Date(img.uploaded).toLocaleString()}
`).join('')}
` return new Response(html, { headers: { 'Content-Type': 'text/html' } }) } // 搜索图片 async function searchImages(env, query, ctx) { const images = await listAllImages(env, ctx) const filtered = images.filter(img => img.key.toLowerCase().includes(query.toLowerCase()) ) return new Response(JSON.stringify(filtered), { headers: { 'Content-Type': 'application/json' } }) } // 获取所有图片列表 async function listAllImages(env, ctx) { // 尝试从KV缓存获取 const cacheKey = 'image-index' const cached = await env.ALBUM_KV.get(cacheKey) if (cached) return JSON.parse(cached) // 从R2获取最新列表 const objects = [] let cursor do { const options = { limit: 1000 } if (cursor) options.cursor = cursor const list = await env.MY_R2_BUCKET.list(options) objects.push(...list.objects.filter(obj => obj.key.match(/\.(jpg|jpeg|png|gif|webp)$/i) )) cursor = list.truncated ? list.cursor : undefined } while (cursor) // 转换为需要的格式 const images = objects.map(obj => ({ key: obj.key, size: obj.size, uploaded: obj.uploaded })) // 缓存结果(TTL 1小时) ctx.waitUntil(env.ALBUM_KV.put(cacheKey, JSON.stringify(images), { expirationTtl: 3600 })) return images } // 代理图片服务 async function serveImage(env, key) { const object = await env.MY_R2_BUCKET.get(key) if (!object) return new Response('Not Found', { status: 404 }) const headers = new Headers() object.writeHttpMetadata(headers) headers.set('Cache-Control', 'public, max-age=31536000') return new Response(object.body, { headers }) } function formatBytes(bytes) { if (bytes === 0) return '0 Bytes' const k = 1024 const sizes = ['Bytes', 'KB', 'MB', 'GB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}` } ``` 可自行修改css样式以适应个人喜好。 ## 部署与测试 1. **部署Worker**:将上述代码复制到Cloudflare Workers的编辑器中,保存并部署。 2. **配置R2和KV**:确保Worker绑定了你创建的R2存储桶(变量使用`MY_R2_BUCKET`)和KV命名空间(变量使用`ALBUM_KV`)。 3. **上传图片**:通过Cloudflare的R2界面上传一些图片到你的存储桶中。 4. **访问相册**:打开浏览器,访问你的Worker URL,应该可以看到相册页面,并且可以搜索和查看图片。 ## 演示 你可以访问以下链接查看演示效果: https://gallery.zxd.im/