一个基于 Cloudflare Workers 的高性能代理服务,提供 OpenAI 图片编辑接口到火山引擎的兼容性转换,支持 FormData 图片上传到 R2 临时存储并自动转换 API 格式。
- 🔄 API 格式转换: OpenAI 图片编辑接口 ↔ 火山引擎 API 无缝转换
- 📁 临时文件存储: FormData 图片自动上传至 Cloudflare R2 存储桶
- 🔑 灵活认证: 支持客户端提供的 API Key,无需预配置
- 🗂️ 智能文件处理: 自动保留原始文件扩展名,支持 MIME 类型推断
- 🕒 自动清理: Cron 定时任务清理过期临时文件(24小时)
- 🧪 全面测试: 完整的单元测试和集成测试覆盖
graph LR
A[客户端应用] --> B[ImgEditWorker]
B --> C[Cloudflare R2]
B --> D[火山引擎 API]
B --> E[定时清理任务]
E --> C
项目需要设置以下环境变量:
| 变量名 | 类型 | 必需 | 描述 | 设置方式 |
|---|---|---|---|---|
AUTH_KEY_SECRET |
Secret | ✅ | 管理接口认证密钥 | wrangler secret put AUTH_KEY_SECRET |
WORKER_URL |
Secret | ✅ | Worker域名(用于临时文件URL) | wrangler secret put WORKER_URL |
安全注意事项:
⚠️ 所有敏感信息均通过wrangler secret设置,不在代码中暴露- ✅
WORKER_URL应设置为实际的 Worker 域名,如:https://your-worker.your-subdomain.workers.dev
- Node.js 18+
- pnpm
- Cloudflare 账号
- 开通并创建 Cloudflare R2 存储桶
- 火山引擎火山方舟 API 密钥
-
克隆仓库
git clone https://github.com/nick3/ImgEditWorker.git cd ImgEditWorker -
安装依赖
pnpm install
-
配置环境
# 设置管理认证密钥(用于清理接口) wrangler secret put AUTH_KEY_SECRET # 设置 Worker URL(用于生成临时文件访问链接) wrangler secret put WORKER_URL # 创建 R2 存储桶 wrangler r2 bucket create img-temp-storage
-
配置验证
确保已设置必需的环境变量:
# 验证 secrets 设置 wrangler secret list
# 启动开发服务器
pnpm dev
# 运行测试
pnpm test
# 测试监视模式
pnpm test --watch项目支持两种部署方式:命令行部署和 Web 界面部署。
# 部署到 Cloudflare
pnpm deploy这种方式无需本地环境配置,适合没有技术背景的用户。
-
访问项目页面
-
Fork 仓库
- 点击页面右上角的 "Fork" 按钮
- 选择您的 GitHub 账户作为目标
- 等待 Fork 完成
-
登录 Cloudflare Dashboard
- 访问 Cloudflare Dashboard
- 使用您的 Cloudflare 账户登录
-
创建新 Worker
- 在左侧菜单中选择 "Workers"下的"Workers & Pages"
- 点击 "Create application" 按钮
- 选择 "Workers" 标签页
- 点击 "Import a repository"
-
连接 GitHub 仓库
- 选择 "GitHub" 作为 Git 提供商
- 如果是首次连接,需要授权 Cloudflare 访问您的 GitHub
- 在仓库列表中找到并选择您刚才 Fork 的
ImgEditWorker仓库 - 点击 "Begin setup"
-
基本设置
- Project name: 输入项目名称(如:
my-imgedit-worker) - Production branch: 选择
main或master - Framework preset: 选择 "None"
- Build command: 留空
- Build output directory: 留空
- Project name: 输入项目名称(如:
-
环境变量配置
- 点击 "Environment variables (advanced)" 展开高级设置
- 添加以下环境变量:
变量名 值 描述 NODE_VERSION18指定 Node.js 版本 点击 "Save and Deploy"
-
创建 R2 存储桶
- 在 Cloudflare Dashboard 中选择 "R2 Object Storage"
- 点击 "Create bucket"
- 存储桶名称输入:
img-temp-storage - 选择合适的位置(建议选择离用户最近的区域)
- 点击 "Create bucket"
-
绑定存储桶到 Worker
- 回到 "Workers & Pages" 页面
- 找到您刚创建的项目,点击进入
- 选择 "Settings" 标签页
- 在左侧菜单选择 "Functions"
- 滚动到 "R2 bucket bindings" 部分
- 点击 "Add binding"
- Variable name:
img_temp_storage - R2 bucket: 选择
img-temp-storage
- Variable name:
- 点击 "Save"
-
设置认证密钥
- 在项目设置页面,选择 "Environment variables"
- 点击 "Add variable"
- 添加以下变量:
变量名 类型 值 描述 AUTH_KEY_SECRETSecret your-auth-key-here管理接口认证密钥,请设置为强密码 WORKER_URLSecret https://your-worker-domain.pages.dev您的 Worker 域名 ⚠️ 重要提示:AUTH_KEY_SECRET请设置为一个强密码,用于保护管理接口WORKER_URL需要等部署完成后获取实际的 Worker 域名再设置
-
保存并重新部署
- 点击 "Save" 保存环境变量
- 系统会自动触发重新部署
-
查看部署状态
- 在项目概览页面查看部署状态
- 等待状态变为 "Success"
-
获取域名
- 部署成功后,您会看到生成的域名(如:
https://my-imgedit-worker.pages.dev) - 复制这个域名
- 部署成功后,您会看到生成的域名(如:
-
更新 WORKER_URL
- 回到 "Environment variables" 设置页面
- 找到
WORKER_URL变量,点击 "Edit" - 将值更新为实际的 Worker 域名
- 点击 "Save"
-
健康检查
curl https://your-worker-domain.pages.dev/health
预期响应:
{ "status": "ok", "timestamp": "2025-09-11T01:10:43.000Z" } -
API 测试
# 使用您设置的 AUTH_KEY_SECRET 和火山引擎 API Key curl -X POST https://your-worker-domain.pages.dev/v1/images/edits \ -H "Authorization: Bearer YOUR_AUTH_KEY_SECRET:YOUR_VOLC_API_KEY" \ -F "prompt=编辑图片描述" \ -F "image=@your-image.png"
现在您的 ImgEditWorker 已经成功部署到 Cloudflare。每当您在 GitHub 上更新代码时,Cloudflare 会自动重新部署您的应用。
- 代码更新: 直接在 GitHub 上编辑代码或接受 Pull Request,Cloudflare 会自动部署
- 查看日志: 在 Cloudflare Dashboard 的项目页面中查看实时日志
- 监控使用: 在 "Analytics" 标签页中查看请求统计和性能指标
- 域名绑定: 如需绑定自定义域名,在 "Custom domains" 中添加
常见问题:
-
部署失败
- 检查 GitHub 仓库是否正确 Fork
- 确认构建设置是否正确(Framework preset 选择 "None")
-
环境变量未生效
- 确认变量类型设置正确(敏感信息选择 "Secret")
- 修改环境变量后需要重新部署才能生效
-
R2 存储桶连接失败
- 检查存储桶绑定的变量名是否为
img_temp_storage - 确认存储桶名称为
img-temp-storage
- 检查存储桶绑定的变量名是否为
-
API 调用失败
- 检查
WORKER_URL是否设置为正确的 Worker 域名 - 确认
AUTH_KEY_SECRET设置正确
- 检查
端点: POST /v1/images/edits
兼容 OpenAI 图片编辑接口格式,支持 FormData 上传。
POST /v1/images/edits
Content-Type: multipart/form-data
Authorization: Bearer AUTH_KEY_SECRET:VOLC_API_KEY
prompt: "编辑描述"
model: "model-name"
n: 1
response_format: "b64_json"
image: [图片文件]认证格式说明:
- Authorization 头部使用组合格式:
Bearer AUTH_KEY_SECRET:VOLC_API_KEY AUTH_KEY_SECRET:系统认证密钥(防止无效请求浪费存储)VOLC_API_KEY:火山引擎 API 密钥(用于调用生成服务)- 两部分用冒号
:分隔
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
prompt |
string | ✅ | 图片编辑的描述文本 |
image |
file | ❌ | 要编辑的图片文件 |
model |
string | ❌ | 使用的模型名称 |
n |
integer | ❌ | 生成图片数量(默认: 1) |
response_format |
string | ❌ | 响应格式:url 或 b64_json(默认: b64_json) |
{
"created": 1234567890,
"data": [
{
"url": "https://generated-image-url.com/image.png",
"b64_json": "base64-encoded-image-data..."
}
],
"usage": {
"total_tokens": 100,
"input_tokens": 50,
"output_tokens": 50
}
}端点: GET /temp/{file-key}
访问上传到 R2 的临时文件。
GET /temp/temp_1234567890_abc123.png端点: GET /health
{
"status": "ok",
"timestamp": "2025-09-11T01:10:43.000Z"
}端点: POST /cron/cleanup
手动触发临时文件清理(需要管理权限)。
POST /cron/cleanup
X-Custom-Auth-Key: YOUR_AUTH_KEY_SECRET- 接收请求: 解析 Authorization 头部的组合 API Key
- 认证验证: 先验证 AUTH_KEY_SECRET 是否正确
- FormData解析: 认证通过后解析图片和参数
- 文件验证: 检查文件类型(JPEG/PNG)和大小(最大 10MB)
- R2 上传: 上传到临时存储并生成访问 URL
- API 转换: 将 OpenAI 格式转换为火山引擎 API 格式
- 调用 API: 使用火山引擎 API Key 调用接口
- 响应转换: 将火山引擎响应转换回 OpenAI 格式
优势: 先验证认证密钥可以防止无效请求浪费 R2 存储空间
临时文件使用以下命名规则:
- 格式:
temp_{timestamp}_{random}{extension} - 扩展名处理:
- 有原始文件名:保留原始扩展名
- 文件名为 "blob":通过 MIME 类型推断扩展名
- 支持的格式:jpg, png, gif, webp, bmp, tiff, svg
- 执行时间: 每天凌晨 2:00(Cron:
0 2 * * *) - 清理规则: 删除超过 24 小时的临时文件
- 手动触发: 通过
/cron/cleanup接口
项目包含完整的测试套件,使用 Vitest 和 Cloudflare Workers 测试池。
- ✅ 认证测试: 组合 API Key 格式验证和双重认证流程
- ✅ 文件上传: FormData 解析和 R2 存储
- ✅ API 转换: OpenAI ↔ 火山引擎格式转换
- ✅ 错误处理: 各种异常场景和安全验证
- ✅ MIME 推断: blob 文件名的扩展名推断
- ✅ 清理功能: 临时文件自动清理
- ✅ 资源保护: 无效认证不消耗 R2 存储
# 运行所有测试
pnpm test
# 详细输出
pnpm test --reporter=verbose
# 特定测试
pnpm test -t "图片编辑"
# 覆盖率报告
pnpm test --coverage- 客户端 API: 使用组合格式
Authorization: Bearer AUTH_KEY:VOLC_API_KEY - 管理接口: 使用
X-Custom-Auth-Key头部认证 - 双重验证: 先验证系统密钥,通过后再上传文件到 R2,最后调用火山引擎 API
- 资源保护: 无效认证请求不会消耗 R2 存储资源
- 类型限制: 仅允许特定图片格式(JPEG/PNG)
- 大小限制: 文件最大 10MB
- 临时存储: 文件自动过期,避免长期占用
- 访问控制: 临时 URL 仅在有效期内可用
- CPU 时间: 最大 10ms(免费版)/ 50ms(付费版)
- 内存: 最大 128MB
- 请求大小: 最大 100MB
- 响应大小: 最大 100MB
- 异步处理: 全面使用 async/await
- 流式上传: 使用 stream() 处理大文件
- 错误处理: 快速失败,避免资源浪费
- 缓存策略: 临时文件设置合适的缓存头
ImgEditWorker/
├── src/
│ └── index.js # 主应用逻辑
├── test/
│ └── index.spec.js # 测试套件
├── package.json # 依赖配置
├── wrangler.jsonc # Cloudflare 配置
├── vitest.config.js # 测试配置
└── README.md # 项目文档
主要方法:
handleImageEdit(): 处理图片编辑请求parseFormDataImages(): 解析 FormData 中的图片uploadImageToR2(): 上传图片到 R2 存储buildVolcEngineRequest(): 构建火山引擎 API 请求callVolcEngineAPI(): 调用火山引擎 APItransformToOpenAIResponse(): 转换响应格式cleanupExpiredFiles(): 清理过期文件
- 扩展 API: 在
ImageEditProxy类中添加新方法 - 路由处理: 在主 fetch 函数中添加新路由
- 编写测试: 在
test/index.spec.js中添加测试用例 - 更新文档: 同步更新 README.md
A: 使用组合格式:AUTH_KEY_SECRET:VOLC_API_KEY,其中 AUTH_KEY_SECRET 是系统认证密钥,VOLC_API_KEY 是火山引擎 API 密钥。
A: 双重验证机制可以防止无效的火山引擎 API Key 浪费 R2 存储空间,先验证系统密钥再处理文件上传。
A: 访问火山引擎开放平台,注册账号并在控制台创建 API Key。
A: 某些客户端会将文件名设为 "blob",系统会自动通过 MIME 类型推断正确的扩展名。
A: 系统每天凌晨 2:00 自动清理超过 24 小时的临时文件,也可以手动调用清理接口。
A: 当前支持 JPEG 和 PNG 格式,文件大小限制为 10MB。
A: 使用 wrangler dev 启动本地开发服务器,使用 console.log 输出调试信息。
本项目采用 MIT 许可证 - 查看 LICENSE 文件了解详情。
欢迎提交 Issue 和 Pull Request!
- Fork 本仓库
- 创建特性分支 (
git checkout -b feature/amazing-feature) - 提交更改 (
git commit -m 'Add amazing feature') - 推送到分支 (
git push origin feature/amazing-feature) - 创建 Pull Request
如果您遇到问题或有疑问,请:
注意: 本项目用于学习和演示目的。在生产环境中使用前,请确保充分测试并review安全配置。