基于 Cloudflare Workers + D1 + R2 的可扩展静态文件展示站 线上地址:https://share.patdelphi.xyz
- 支持类型:md / html / txt / json / css / js / 图片(png/jpg/jpeg/gif/webp/bmp/svg)/ 视频(mp4/webm/ogg/ogv/mov)
- 单文件 ≤ 50MB
- 服务端渲染:Markdown 自动转 HTML,自动暗色/亮色主题切换
- HTML 文件直接返回原文(不套模板,保留原始样式)
- 图片展示页:按钮缩放 + 热键(
=放大 /-缩小 /0复位)+ 下载 - 视频展示页:原生 video 控件(播放/暂停/进度/音量/全屏)+ 下载
- 视频支持 Range 请求(HTTP 206 Partial Content),可拖动进度条 seek
- 公开文件直读;私密文件密码访问(bcrypt 哈希 + 24h Cookie 缓存)
- 文件有效期(expires_at,过期返回 410)
- 每日访问上限(daily_view_limit,超限返回 429)
- 动态网址:每个文件生成唯一 slug,访问地址
/f/:slug,不暴露原始文件名
- 仪表盘:8 列精简表格,状态用彩色 badge(绿=公开/棕=私密/灰=隐藏)
- 单文件上传:表单提交,可设置标题/分类/标签/密码/有效期/访问上限
- 批量上传:拖拽多文件 + 批量属性 + 串行上传 + 进度条 + 结果列表
- 编辑、删除、展示开关
- Sticky header + 暗色模式适配
- 首页(
/):最近公开文件列表,分页 - 目录(
/list):表格形式分页展示(仅根目录文件 + 顶层公开文件夹入口) - 搜索(
/search?q=):按标题/文件名模糊匹配,分页 - 文件夹(
/folder/:slug):面包屑 + 子文件夹卡片 + 文件列表分页,支持密码保护 - 分页控件:首页/上一页/页码/下一页/末页 + 每页 10/20/50/100 条选择
- 二维码:服务端生成 SVG,无外部 CDN 依赖
- 嵌套层级最大 3 层,业务层校验防止超限
- 循环引用检测:文件夹不能移到自身或子文件夹下
- 非空目录拒绝删除(含子文件或子文件夹时返回 400)
- Slug 全局唯一:
folders.slug与files.slug共享命名空间 - 密码复用:文件夹直接复用文件的 bcrypt + JWT 鉴权机制
- 批量移动:仪表盘支持批量将文件移动到指定文件夹
- 文件夹管理页:
/admin/folders(面包屑导航 + 子文件夹表 + 文件表) - 统计页:显示文件夹总数 + Top 5 文件夹(按文件数排序)
- Bearer Token 鉴权,供 Python 脚本批量操作
- POST
/api/upload上传、GET/api/files列出、DELETE/api/files/:id删除
| 组件 | 用途 |
|---|---|
| Cloudflare Workers | 边缘计算(路由、渲染、鉴权) |
| D1 | 文件元数据与权限存储(SQLite 托管) |
| R2 | 原始文件存储(对象存储,支持 Range 读取) |
| Workers Secrets | 管理员凭证与 JWT 密钥 |
| TypeScript | 主开发语言 |
| markdown-it | Markdown 渲染 |
| bcryptjs | 密码哈希 |
| @tsndr/cloudflare-worker-jwt | JWT 签发与校验 |
| qrcode-generator | 服务端二维码生成 |
cloudflare/
├── src/
│ ├── index.ts # 主入口,路由与业务逻辑(含 Range 请求支持)
│ ├── db.ts # D1 CRUD 封装(事务)
│ ├── r2.ts # R2 读写封装
│ ├── auth.ts # JWT + bcrypt 鉴权
│ └── render.ts # MD 渲染 + 模板(图片/视频/后台)
├── migrations/
│ ├── 0001_init.sql # D1 初始表结构
│ ├── 0002_add_limits_and_expiry.sql # 有效期与访问上限字段
│ └── 0003_add_folders.sql # 文件夹表 + files.folder_id
├── scripts/
│ └── upload.py # Python 上传脚本
├── test/ # 单元测试(53 个)
├── Docs/ # 项目文档
├── wrangler.toml # Workers 配置
├── package.json
└── tsconfig.json
npm install
npm run dev
# 访问 http://127.0.0.1:8787npm run deploy详细部署步骤见 Docs/deployment.md。
- 访问
/admin/login - 输入用户名和密码登录
- 在仪表盘上传、编辑、删除文件
- 单文件上传走表单;批量上传走拖拽区
- 通过开关控制文件公开/私密、是否列出
# 设置 Token
export FILESTATION_TOKEN=<你的 API Token>
export FILESTATION_SITE=https://share.patdelphi.xyz
# 上传公开文件
python scripts/upload.py readme.md --public --title "项目说明"
# 上传带密码的私密文件
python scripts/upload.py secret.txt --password 123456
# 查看所有参数
python scripts/upload.py --help- 首页:
https://share.patdelphi.xyz/ - 目录:
https://share.patdelphi.xyz/list - 搜索:
https://share.patdelphi.xyz/search?q=关键词 - 文件:
https://share.patdelphi.xyz/f/<slug> - 原文:
https://share.patdelphi.xyz/f/<slug>/raw - 文件夹:
https://share.patdelphi.xyz/folder/<slug>
=或+:放大-或_:缩小0:复位
详细文档见 Docs/api.md。
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| POST | /api/upload | Bearer Token | 上传文件 |
| GET | /api/files | Bearer Token | 列出全部文件 |
| DELETE | /api/files/:id | Bearer Token | 删除文件 |
npm run dev # 启动本地开发
npm run deploy # 部署到生产
npm run type-check # TypeScript 类型检查
npm test # 运行单元测试
npm run db:migrate:local # 本地数据库迁移
npm run db:migrate:remote# 远程数据库迁移- 所有敏感凭证(ADMIN_USERNAME、ADMIN_PASSWORD、JWT_SECRET、API_TOKEN)通过
wrangler secret put配置,不进代码仓库 .dev.vars已在.gitignore中,本地开发凭证不会被提交- D1 写操作使用事务(batch)保证原子性
- 密码使用 bcrypt 哈希存储,不可逆
- 文件访问受密码、有效期、每日访问上限三重保护
- Workers 免费版 CPU 限制 10ms/请求
- D1 免费版每日 5M 行读取、100K 行写入、5GB 存储
- R2 免费版 10GB 存储、1M 次 A 类操作/月、10M 次 B 类操作/月
- 单文件 ≤ 50MB(可配置
MAX_FILE_SIZE)
MIT