Skip to content

用 Cloudflare 免费方案建立自己的图库,真的 $0 起步

你有没有想过,把自己常用的免费商用图片集中管理,建一个自己的图库入口,搜索一下就能找到——而且完全不花钱?

我们做了,这篇文章分享整个架构怎么搭。


先说为什么要自己建

做设计、做网站、做营销,免不了找图。Pixabay、Pexels、Unsplash 都很好用,但每次都要各自打开、各自搜索,时间碎片化。

更烦的是:你用过一张图,下次根本不记得在哪找到的。

如果能有一个自己的图库入口,把常用来源全部整合进去,搜索一次横扫所有来源,那才是省时间的方式。

这就是我们做 FreePicHub 自由图汇 的出发点。


Cloudflare 免费额度有多够用

很多人不知道 Cloudflare 有多慷慨。以下是这个项目实际用到的服务,全部在免费方案内:

服务用途免费额度
R2 对象存储存图片文件10 GB 存储 / 每月 1,000 万次 GET
D1 数据库存图片 metadata5 GB 存储 / 每日 500 万次读取
WorkersAPI 后端每日 10 万次请求
Pages前端网站无限静态部署

一个小型到中型的个人图库,这个额度完全够用,而且不需要信用卡就能开始。


整体架构

[Python 自动化导入脚本]

  图片处理 (WebP 压缩)

 ┌──────────────────┐
 │    Cloudflare    │
 │                  │
 │  R2 (图片文件)   │
 │  D1 (数据库)     │
 │  Workers (API)   │
 │  Pages (前端)    │
 └──────────────────┘

    浏览器用户

四个 Cloudflare 服务各司其职:

  • R2:放压缩过的图片(缩略图 / 预览图 / 原图)
  • D1:SQLite 数据库,存标题、尺寸、标签、图片的 R2 路径
  • Workers:写两支 API — /api/search/api/featured
  • Pages:静态前端,纯 HTML + CSS + JS,无框架依赖

Step 1:建立 R2 Bucket

进 Cloudflare Dashboard → R2 → 创建 Bucket,名称自定(例如 my-image-library)。

接着到 Manage R2 API Tokens,创建一个 User API Token:

  • 权限选「Object Read & Write」
  • 限定套用到你的 Bucket

记下 Access Key ID、Secret Access Key、账号 ID,之后 Python 脚本会用到。

R2 是 S3 兼容 API,所以 Python 端用 boto3 就能直接操作,不需要学新的 SDK。


Step 2:建立 D1 数据库

在 Wrangler CLI 执行:

bash
npx wrangler d1 create my-image-db

记下返回的 database_id。然后建立 Schema:

sql
CREATE TABLE IF NOT EXISTS images (
  id            TEXT PRIMARY KEY,
  source        TEXT NOT NULL,
  source_id     TEXT,
  title         TEXT,
  tags          TEXT DEFAULT '[]',
  width         INTEGER,
  height        INTEGER,
  aspect_ratio  TEXT,
  license_type  TEXT NOT NULL,
  thumb_key     TEXT,
  preview_key   TEXT,
  original_key  TEXT,
  created_at    TEXT DEFAULT (datetime('now'))
);

CREATE INDEX IF NOT EXISTS idx_source    ON images(source);
CREATE INDEX IF NOT EXISTS idx_created   ON images(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_source_id ON images(source, source_id);
bash
npx wrangler d1 execute my-image-db --file=schema.sql

Step 3:Workers API(用 Pages Functions)

最方便的做法是用 Cloudflare Pages Functions,直接把 JS 放在 /functions 目录下,Cloudflare 会自动部署成 Worker。

搜索 API (functions/api/search.js):

javascript
export async function onRequestGet({ request, env }) {
  const url    = new URL(request.url)
  const q      = url.searchParams.get('q') || ''
  const source = url.searchParams.get('source') || ''
  const page   = parseInt(url.searchParams.get('page') || '1')
  const limit  = 24
  const offset = (page - 1) * limit

  let sql    = 'SELECT * FROM images WHERE 1=1'
  let params = []

  if (q) {
    sql += ' AND (title LIKE ? OR tags LIKE ?)'
    params.push(`%${q}%`, `%${q}%`)
  }
  if (source) {
    sql += ' AND source = ?'
    params.push(source)
  }

  sql += ` ORDER BY created_at DESC LIMIT ${limit + 1} OFFSET ${offset}`

  const { results } = await env.MY_DB.prepare(sql).bind(...params).all()
  const hasMore = results.length > limit

  return Response.json({
    results: results.slice(0, limit).map(r => ({
      ...r,
      tags: JSON.parse(r.tags || '[]')
    })),
    has_more: hasMore
  }, { headers: { 'Access-Control-Allow-Origin': '*' } })
}

Step 4:图片处理与自动化导入

这是整个系统最有趣的部分。写一支 Python 脚本,把图片处理后上传到 R2,metadata 写入 D1。

图片处理:每张图产出三个版本,全部存成 WebP

python
from PIL import Image

def process_image(source_path, output_dir):
    img = Image.open(source_path).convert("RGB")
    w, h = img.size

    # 缩略图 512px(前端列表用)
    thumb = img.copy()
    thumb.thumbnail((512, 512), Image.LANCZOS)
    thumb.save(output_dir / "thumb.webp", "WEBP", quality=82)

    # 预览图 1024px(点开 modal 用)
    preview = img.copy()
    preview.thumbnail((1024, 1024), Image.LANCZOS)
    preview.save(output_dir / "preview.webp", "WEBP", quality=85)

    # 原图转 WebP 压缩后保存
    img.save(output_dir / "original.webp", "WEBP", quality=90)

    return {"width": w, "height": h}

WebP 格式比 JPEG 通常小 25–35%,长期下来 R2 存储成本差很多。

上传到 R2(boto3 S3 兼容接口)

python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url=f"https://{ACCOUNT_ID}.r2.cloudflarestorage.com",
    aws_access_key_id=ACCESS_KEY,
    aws_secret_access_key=SECRET_KEY,
    region_name="auto",
)
s3.put_object(Bucket="my-image-library", Key="source/uuid/thumb.webp", Body=file_bytes)

写入 D1(防止重复写入的关键)

python
import requests, uuid, json

def write_to_d1(record):
    resp = requests.post(
        f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/d1/database/{DB_ID}/query",
        headers={"Authorization": f"Bearer {D1_TOKEN}"},
        json={
            "sql": """
                INSERT INTO images (id, source, source_id, title, tags,
                  width, height, aspect_ratio, license_type,
                  thumb_key, preview_key, original_key)
                SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
                WHERE NOT EXISTS (
                  SELECT 1 FROM images WHERE source=? AND source_id=?
                )
            """,
            "params": [str(uuid.uuid4()), record["source"], record["source_id"],
                       record["title"], json.dumps(record["tags"]),
                       record["width"], record["height"], record["aspect_ratio"],
                       record["license_type"], record["thumb_key"],
                       record["preview_key"], record["original_key"],
                       record["source"], record["source_id"]]
        }
    )
    return resp.json().get("success", False)

WHERE NOT EXISTS 让你重复执行脚本也不会写入重复数据——这个设计让整个系统可以安心地每天定时跑。


Step 5:前端部署

前端三个静态文件:index.htmlstyle.cssapp.js,推上 Cloudflare Pages:

bash
npx wrangler pages deploy ./frontend --project-name my-image-library

CSS masonry 瀑布流排版,完全不需要 JS 套件:

css
.image-grid {
  columns: 4 220px;
  gap: 14px;
}
.image-card {
  break-inside: avoid;
  margin-bottom: 14px;
}

成本试算

以每天导入 500 张、图库规模 10,000 张计算(缩略图约 50KB、预览图约 200KB):

项目用量费用
R2 存储≈ 2.5 GB$0
D1 读取(日访客 1,000 人)5,000 次/日$0
Workers 请求5,000 次/日$0
Pages 部署无限次$0
总计$0 / 月

Cloudflare 的免费额度对个人或小型商业图库来说几乎用不完。等规模到几十万张、日访客破万,再评估要不要升级方案。


小结

整个系统的核心思想很简单:

  1. R2 负责存文件,便宜又快
  2. D1 负责存索引,搜索靠它
  3. Workers 负责查询逻辑
  4. Pages 负责呈现给用户
  5. Python 脚本 负责定期喂数据进去

全部跑在 Cloudflare edge network 上,全球加速,零维护成本。

如果你也想建一个自己的图库,技术门槛其实没有想象中高——只要会基本的 Python 和 JavaScript,这套架构完全可以在一个周末内跑起来。

实际成品可以参考:FreePicHub 自由图汇


有技术规格或架构问题想咨询?
欢迎来 ascentek.info 联系我们,无论是 Cloudflare 架构设计、Python 自动化流程,或是图库建置规划,我们很乐意讨论。


延伸阅读

Ascentek数字知识库