目录
- 项目简介
- 环境准备
- 项目结构
- 第一步:创建 Worker 项目
- 第二步:创建 KV 命名空间
- 第三步:创建 R2 存储桶
- 第四步:配置 wrangler.toml
- 第五步:编写 worker.js
- 第六步:部署
- 常见问题
项目简介
基于 Cloudflare Workers + KV + R2 搭建的留言板应用:
- Workers — 运行后端 API 和前端页面(边缘计算,全球加速)
- KV — 存储留言数据(键值对数据库)
- R2 — 存储上传的图片(对象存储)
功能:发表留言、表情选择、图片上传、图片预览
在线地址:https://message-board-api.manle.workers.dev/
环境准备
1. 注册 Cloudflare 账号
前往 https://dash.cloudflare.com/sign-up 注册。
2. 安装 Node.js
前往 https://nodejs.org 下载安装 LTS 版本。
3. 安装 Wrangler CLI
1 | npm install -g wrangler |
4. 登录 Cloudflare
1 | wrangler login |
浏览器会打开授权页面,确认授权即可。
验证登录:
1 | wrangler whoami |
项目结构
1 | message-board/ |
第一步:创建 Worker 项目
创建项目目录并进入:
1 | mkdir message-board |
第二步:创建 KV 命名空间
KV 用于存储留言数据。
1 | wrangler kv namespace create "MESSAGE_BOARD" |
输出示例:
1 | ✨ Success! |
重要:记下输出的
id,下一步配置要用。
第三步:创建 R2 存储桶
R2 用于存储上传的图片。
1 | wrangler r2 bucket create message-board-images |
输出:
1 | ✅ Created bucket 'message-board-images' |
第四步:配置 wrangler.toml
在项目根目录创建 wrangler.toml:
1 | name = "message-board-api" |
配置说明
| 字段 | 作用 |
|---|---|
name |
Worker 名称,也是域名前缀(name.workers.dev) |
main |
入口文件 |
compatibility_date |
运行时兼容性日期 |
binding |
在代码中通过 env.XXX 访问资源的变量名 |
id / bucket_name |
实际绑定的资源标识 |
第五步:编写 worker.js
5.1 后端 API
1 | const KV_NAMESPACE = 'MESSAGE_BOARD'; // 与 wrangler.toml 中的 binding 一致 |
5.2 前端页面
getHtml() 函数返回完整的 HTML 页面,包含以下功能:
表情选择器
1 | // 使用 Unicode 字符而非 HTML 实体(HTML 实体存入 textarea 会变成纯文本) |
图片上传(前端压缩)
1 | async function handleFileSelect(event) { |
留言展示(含图片)
1 | const imgHtml = msg.imageKey |
第六步:部署
1 | wrangler deploy |
输出示例:
1 | Your Worker has access to the following bindings: |
部署完成后访问 https://你的name.workers.dev 即可使用。
本地开发调试
1 | wrangler dev |
本地启动开发服务器,默认地址 http://localhost:8787。
常见问题
1. kv.get is not a function
原因:wrangler.toml 中的 binding 名称与代码中的不一致。
1 | # wrangler.toml |
1 | // worker.js |
2. Cannot read properties of undefined (reading 'get')
原因:KV 命名空间绑定未配置或绑定名称错误。检查 wrangler.toml 中的 binding 是否正确。
3. 表情显示为 😊
原因:使用了 HTML 实体而非 Unicode 字符。
1 | // ❌ 错误 — HTML 实体存入 textarea 变成纯文本 |
4. 部署时提示绑定冲突
本地 wrangler.toml 的配置会覆盖云端配置。如果云端已有绑定但名称不同,部署时会提示差异,确认即可覆盖。
5. R2 图片上传失败
检查 wrangler.toml 中 R2 配置:
1 | [[r2_buckets]] |
API 接口汇总
| 方法 | 路径 | 说明 | 请求体 |
|---|---|---|---|
| GET | /api/messages |
获取所有留言 | — |
| POST | /api/messages |
发表留言 | { name, content, imageKey? } |
| POST | /api/upload |
上传图片 | FormData: image |
| GET | /api/image/:key |
访问图片 | — |
| GET | / |
留言板页面 | — |
补充内容
留言板样式在哪里修改
样式都在 worker.js 的 getHtml() 函数里,是内嵌的 CSS。
具体位置:
| 文件 | 行号范围 | 内容 |
|---|---|---|
| worker.js | 约第 70-170 行 | <style> 标签内的 CSS |
主题色修改点:
1 | /* 留言板 - 背景渐变 */ |
“今日话题”用的是粉红渐变(#f093fb → #f5576c),同样在 worker.js 的 getHtml() 中修改。
两个项目结构一样,都在各自的 worker.js 文件里的 getHtml() 函数中改 CSS。
Cloudflare 创建留言板添加表情包和上传的图片功能可以用哪些方式
⏺ Cloudflare Workers 留言板实现表情和图片上传,有以下几种方式:
表情功能
┌──────────┬─────────────────────┬───────────────────────────────────────┐
│ 方式 │ 说明 │ 优缺点 │
├──────────┼─────────────────────┼───────────────────────────────────────┤
│ Unicode │ 直接用 \u{1F60A} 等 │ 最简单,无需依赖,兼容性好 │
│ Emoji │ Unicode 字符 │ │
├──────────┼─────────────────────┼───────────────────────────────────────┤
│ Emoji │ 引用 emoji-mart、em │ 功能丰富(搜索、分类),但增加页面体 │
│ Picker │ oji-button │ 积 │
│ 库 │ 等第三方库 │ │
├──────────┼─────────────────────┼───────────────────────────────────────┤
│ 图片表情 │ 自定义表情图片存 │ 可用自定义表情(如表情包),但需额外 │
│ 包 │ R2,通过 URL 引用 │ 存储和加载 │
└──────────┴─────────────────────┴───────────────────────────────────────┘
图片上传存储
┌──────────┬───────────────┬──────────────────────────────────────────────┐
│ 方式 │ 说明 │ 优缺点 │
├──────────┼───────────────┼──────────────────────────────────────────────┤
│ Cloudfla │ Worker 通过 │ 专业对象存储,免费额度大(10GB+100万次读取/ │
│ re R2 │ env.IMAGES.pu │ 月),推荐 │
│ │ t() 存入 R2 │ │
├──────────┼───────────────┼──────────────────────────────────────────────┤
│ KV 存 │ 图片转 base64 │ 实现最简单,无需额外资源,但 base64 │
│ Base64 │ 直接存入 KV │ 体积增大约 33%,单值上限 25MB │
├──────────┼───────────────┼──────────────────────────────────────────────┤
│ │ 上传到 │ │
│ 外链图床 │ imgur、SM.MS │ 不占自己的存储,但依赖第三方服务 │
│ │ 等图床,存 │ │
│ │ URL │ │
├──────────┼───────────────┼──────────────────────────────────────────────┤
│ Cloudfla │ 使用 │ │
│ re │ Cloudflare │ 自带裁剪/优化,但收费($1/月/1000张) │
│ Images │ Images 服务 │ │
└──────────┴───────────────┴──────────────────────────────────────────────┘
图片压缩方式
┌──────────────────┬──────────────────────────────────────────────────────┐
│ 方式 │ 说明 │
├──────────────────┼──────────────────────────────────────────────────────┤
│ 前端 Canvas 压缩 │ 用 canvas.toBlob() 在浏览器端缩放+压缩,减少上传体积 │
├──────────────────┼──────────────────────────────────────────────────────┤
│ Worker 端压缩 │ 用 @cf/wasm/image 等在 Worker 中处理,但计算资源有限 │
├──────────────────┼──────────────────────────────────────────────────────┤
│ 不压缩直接上传 │ 最简单,但大图会慢 │
└──────────────────┴──────────────────────────────────────────────────────┘
当前项目采用的方案
- 表情:Unicode Emoji(最轻量)
- 图片存储:Cloudflare R2(最稳定)
- 图片压缩:前端 Canvas 压缩(最大 800px 宽,JPEG 质量 0.7)
如果你想换方案或增加功能,告诉我具体需求。
❯ 图片上传存储我用的是哪种方式
⏺ 用的是 Cloudflare R2。
在 wrangler.toml 中配置:
[[r2_buckets]]
binding = “IMAGES”
bucket_name = “message-board-images”
在 worker.js 中通过 env.IMAGES.put() 存入,env.IMAGES.get() 读取。
https://message-board-api.manle.workers.dev 有哪些cdn加速
⏺ message-board-api.manle.workers.dev 部署在 Cloudflare Workers 上,自带
Cloudflare CDN 全球加速,无需额外配置。
已有的 CDN 加速
┌───────────────┬──────────────────────────────────────────────┬──────────┐
│ 功能 │ 说明 │ 状态 │
├───────────────┼──────────────────────────────────────────────┼──────────┤
│ 全球边缘节点 │ Cloudflare 在 300+ 城市有节点,请求就近响应 │ 自动开启 │
├───────────────┼──────────────────────────────────────────────┼──────────┤
│ 静态资源缓存 │ HTML/JS/CSS/图片自动缓存到边缘 │ 自动开启 │
├───────────────┼──────────────────────────────────────────────┼──────────┤
│ HTTP/2 & │ 支持最新协议,多路复用 │ 自动开启 │
│ HTTP/3 │ │ │
├───────────────┼──────────────────────────────────────────────┼──────────┤
│ Brotli 压缩 │ 传输时自动压缩,比 gzip 更高效 │ 自动开启 │
├───────────────┼──────────────────────────────────────────────┼──────────┤
│ 图片缓存 │ R2 图片设置了 Cache-Control: │ 已配置 │
│ │ max-age=31536000,浏览器和 CDN 都会缓存 │ │
└───────────────┴──────────────────────────────────────────────┴──────────┘
你的 Worker 代码中已做的优化
// 图片访问 - 设置了 1 年缓存
headers.set(‘Cache-Control’, ‘public, max-age=31536000’);
// CORS 头 - 允许跨域
‘Access-Control-Allow-Origin’: ‘*’
如果需要更强的加速
┌─────────────────┬────────────────────────────────────────────────────────┐
│ 方式 │ 说明 │
├─────────────────┼────────────────────────────────────────────────────────┤
│ 自定义域名 │ 绑定自己的域名(如 msg.example.com),可开启更多 │
│ │ Cloudflare 功能 │
├─────────────────┼────────────────────────────────────────────────────────┤
│ Workers Paid │ $5/月,CPU 时间从 10ms 提升到 30s,请求无限制 │
│ 计划 │ │
├─────────────────┼────────────────────────────────────────────────────────┤
│ Cache API │ 在 Worker 中用 caches.default 手动缓存动态响应 │
└─────────────────┴────────────────────────────────────────────────────────┘
目前免费计划已经够用,Cloudflare 的 CDN 是开箱即用的,不需要额外配置。
以下是 message-board-api Worker 的域名绑定情况:
域和路由:
类型 地址
workers.dev 子域名 message-board-api.manle.workers.dev
自定义域名 fuliefu.bbroot.com
路由 无
绑定:
R2 存储桶:message-board-images(绑定名 IMAGES)
KV 命名空间:MESSAGE_BOARD
其他信息:
最近一次部署:18 小时前(通过 Wrangler)
24 小时请求量:267 次,3 个错误
