mcpField
C
cloudflare-images

cloudflare-images

github.com/jackspace云与 DevOps1639 次安装12 周前更新
代码仓库

关于 cloudflare-images

cloudflare-images 是 Cloudflare Images 的操作指南,面向需要存储、投放和处理图像的开发者。内容涵盖 Images API、图像转换及变体,并说明公开图像和私有图像的处理方式。

主要功能

  1. 01上传文件或导入外部图像
  2. 02为用户生成直接上传链接
  3. 03转换图像尺寸、格式和效果
  4. 04管理命名及灵活变体
  5. 05使用签名 URL 投放私有图像

适用场景

  1. 01将外部图像迁移到 Cloudflare Images
  2. 02让用户在不暴露 API 密钥的情况下上传
  3. 03按设备尺寸提供响应式图像
  4. 04通过限时链接分享私有图像

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jackspace/claudeskillz --skill cloudflare-images

安装后在 Claude Code 中输入/cloudflare-images确认已加载。

附带文件README.mdSKILL.json

详细介绍

Cloudflare Images

状态:已投入生产 ✅ 最后更新:2025-10-26 依赖项:已启用 Images 的 Cloudflare 账户 最新版本:Cloudflare Images API v2


概述

Cloudflare Images 提供两项强大的功能:

  1. Images API:上传、存储和提供图像,并自动进行优化和生成变体
  2. 图像转换:调整任意公开可访问图像的大小、优化图像并进行转换

主要优势:

  • 通过全球 CDN 分发
  • 自动转换为 WebP/AVIF 格式
  • 适用于不同场景的变体(最多 100 个)
  • 创作者直接上传(用户上传时无需 API 密钥)
  • 用于私有图像的签名 URL
  • 通过 URL 或 Workers 转换任意图像

快速开始(5 分钟)

1. 启用 Cloudflare Images

登录 Cloudflare 控制面板 → Images → 为你的账户启用。

获取你的 Account ID,并创建具有 Cloudflare Images: Edit 权限的 API 令牌。

重要原因:

  • 所有 API 操作都需要 Account ID 和 API 令牌
  • Images 免费套餐包含有限次数的转换
2. 上传你的第一张图像
curl --request POST \
  --url https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/images/v1 \
  --header 'Authorization: Bearer <API_TOKEN>' \
  --header 'Content-Type: multipart/form-data' \
  --form 'file=@./image.jpg'

响应包含:

  • id:用于提供图像的图像 ID
  • variants:提供图像的 URL 数组

重要:

  • 使用 multipart/form-data 编码(而非 application/json)
  • 图像 ID 会自动生成(也可使用自定义 ID)
3. 提供图像
<img src="https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/public" />

默认的 public 变体用于提供图像。替换为你自己的变体名称。

4. 启用图像转换

控制面板 → Images → Transformations → 选择你的区域 → Enable for zone

现在你可以转换任意图像:

<img src="/cdn-cgi/image/width=800,quality=85/uploads/photo.jpg" />

重要原因:

  • 适用于存储在 Cloudflare Images 之外的图像
  • 在 Cloudflare 的全球网络上自动缓存
  • 无需额外的存储费用
5. 通过 Workers 转换(高级)
export default {
  async fetch(request: Request): Promise<Response> {
    const imageURL = "https://example.com/image.jpg";

    return fetch(imageURL, {
      cf: {
        image: {
          width: 800,
          quality: 85,
          format: "auto" // WebP/AVIF for supporting browsers
        }
      }
    });
  }
};

三项功能系统

功能 1:Images API(上传与存储)

将图像存储在 Cloudflare 网络上,并在全球范围内提供。

上传方式:

  1. 文件上传 - 直接从你的服务器上传文件
  2. 通过 URL 上传 - 从外部 URL 导入图像
  3. 创作者直接上传 - 为用户上传生成一次性上传 URL

提供方式:

  • 默认域名:imagedelivery.net
  • 自定义域名:/cdn-cgi/imagedelivery/...
  • 签名 URL:带有过期令牌的私有图像

参见:templates/upload-api-basic.ts、templates/direct-creator-upload-backend.ts

功能 2:图像转换

优化和调整任意图像(存储在 Images 中或外部)。

两种方式:

  1. URL 转换 - 特殊 URL 格式
  2. Workers 转换 - 通过 fetch 进行程序化控制

常见转换:

  • 调整大小:width=800,height=600,fit=cover
  • 优化:quality=85,format=auto
  • 效果:blur=10,sharpen=3
  • 裁剪:gravity=face,zoom=0.5

参见:templates/transform-via-url.ts、templates/transform-via-workers.ts

功能 3:变体

为不同使用场景预定义图像尺寸。

命名变体(最多 100 个):

  • 创建一次,随处使用
  • 示例:thumbnail、avatar、hero
  • 转换效果一致

灵活变体(动态):

  • 按账户启用
  • 在 URL 中使用转换参数
  • 示例:w=400,sharpen=3
  • 不能与签名 URL 配合使用

参见:templates/variants-management.ts、references/variants-guide.md


Images API - 上传方式

方式 1:文件上传(基础)
curl --request POST \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1 \
  --header "Authorization: Bearer <API_TOKEN>" \
  --header "Content-Type: multipart/form-data" \
  --form 'file=@./image.jpg' \
  --form 'requireSignedURLs=false' \
  --form 'metadata={"key":"value"}'

关键选项:

  • file:图像文件(必需)
  • id:自定义 ID(可选,默认自动生成)
  • requireSignedURLs:私有图像设为 true(默认:false)
  • metadata:JSON 对象(最大 1024 字节,终端用户不可见)

响应:

{
  "result": {
    "id": "2cdc28f0-017a-49c4-9ed7-87056c83901",
    "filename": "image.jpg",
    "uploaded": "2022-01-31T16:39:28.458Z",
    "requireSignedURLs": false,
    "variants": [
      "https://imagedelivery.net/Vi7wi5KSItxGFsWRG2Us6Q/2cdc28f0.../public"
    ]
  }
}

参见:templates/upload-api-basic.ts

方法 2:通过 URL 上传

无需先下载,即可从外部来源导入图片。

curl --request POST \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1 \
  --header "Authorization: Bearer <API_TOKEN>" \
  --form 'url=https://example.com/image.jpg' \
  --form 'metadata={"source":"external"}'

适用场景:

  • 从其他服务迁移图片
  • 导入用户提供的 URL
  • 备份外部来源的图片

重要提示:

  • URL 必须可公开访问,或需要通过身份验证
  • 支持 HTTP 基本身份验证:https://user:[email protected]/image.jpg
  • 同一请求中不能同时使用 file 和 url

参见:templates/upload-via-url.ts

方法 3:创建者直接上传 ⭐

生成一次性上传 URL,让用户直接上传到 Cloudflare(无需暴露 API 密钥)。

后端端点(生成上传 URL):

const response = await fetch(
  `https://api.cloudflare.com/client/v4/accounts/${accountId}/images/v2/direct_upload`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      requireSignedURLs: true,
      metadata: { userId: '12345' },
      expiry: '2025-10-26T18:00:00Z' // Optional: default 30min, max 6hr
    })
  }
);

const { uploadURL, id } = await response.json();
// Return uploadURL to frontend

前端上传(HTML + JavaScript):

<form id="upload-form">
  <input type="file" id="file-input" accept="image/*" />
  <button type="submit">Upload</button>
</form>

<script>
document.getElementById('upload-form').addEventListener('submit', async (e) => {
  e.preventDefault();

  const fileInput = document.getElementById('file-input');
  const formData = new FormData();
  formData.append('file', fileInput.files[0]); // MUST be named 'file'

  const uploadURL = 'UPLOAD_URL_FROM_BACKEND'; // Get from backend

  const response = await fetch(uploadURL, {
    method: 'POST',
    body: formData // NO Content-Type header, browser sets multipart/form-data
  });

  if (response.ok) {
    console.log('Upload successful!');
  }
});
</script>

重要原因:

  • 不会向浏览器暴露 API 密钥
  • 用户直接上传到 Cloudflare(速度更快,无需中间服务器)
  • 一次性 URL 在使用后或超时后失效
  • 可通过 Webhook 接收上传成功或失败通知

关键 CORS 修复:

  • ✅ 应当:使用 multipart/form-data 编码(由浏览器设置标头)
  • ✅ 应当:将字段命名为 file(而不是 image 或其他名称)
  • ✅ 应当:仅从后端调用 /direct_upload API
  • ❌ 不要:设置 Content-Type: application/json 或 image/jpeg
  • ❌ 不要:从浏览器调用 /direct_upload(CORS 会失败)

参见:templates/direct-creator-upload-backend.ts、templates/direct-creator-upload-frontend.html、references/direct-upload-complete-workflow.md


图片转换

URL 转换

使用特殊 URL 格式转换图片。

URL 格式:

https://<ZONE>/cdn-cgi/image/<OPTIONS>/<SOURCE-IMAGE>

示例:

<img src="/cdn-cgi/image/width=800,quality=85,format=auto/uploads/photo.jpg" />

常用选项:

  • 尺寸:width=800、height=600、fit=cover
  • 质量:quality=85(1-100)
  • 格式:format=auto(自动检测 WebP/AVIF)、format=webp、format=jpeg
  • 裁剪:gravity=auto(智能裁剪)、gravity=face、trim=10
  • 效果:blur=10、sharpen=3、brightness=1.2、contrast=1.1
  • 旋转:rotate=90、flip=h(水平翻转)、flip=v(垂直翻转)

适配选项:

  • scale-down:缩小以适配(不会放大)
  • contain:调整大小以适配尺寸(保持宽高比)
  • cover:调整大小以填满尺寸(可能会裁剪)
  • crop:裁剪至指定尺寸
  • pad:调整大小并添加内边距(与 background 选项搭配使用)

格式自动检测:

<img src="/cdn-cgi/image/format=auto/image.jpg" />

Cloudflare 会提供:

  • 向支持 AVIF 的浏览器(Chrome、Edge)提供 AVIF
  • 向不支持 AVIF 的浏览器(Safari、Firefox)提供 WebP
  • 以原始格式(JPEG)作为后备格式

参见:templates/transform-via-url.ts、references/transformation-options.md

Workers 转换

使用自定义 URL 方案以编程方式转换图片。

基本模式:

export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);

    // Custom URL scheme: /images/thumbnail/photo.jpg
    if (url.pathname.startsWith('/images/thumbnail/')) {
      const imagePath = url.pathname.replace('/images/thumbnail/', '');
      const imageURL = `https://storage.example.com/${imagePath}`;

      return fetch(imageURL, {
        cf: {
          image: {
            width: 300,
            height: 300,
            fit: 'cover',
            quality: 85
          }
        }
      });
    }

    return new Response('Not found', { status: 404 });
  }
};

进阶:内容协商:

const accept = request.headers.get('accept') || '';

let format: 'avif' | 'webp' | 'auto' = 'auto';
if (/image\/avif/.test(accept)) {
  format = 'avif';
} else if (/image\/webp/.test(accept)) {
  format = 'webp';
}

return fetch(imageURL, {
  cf: {
    image: {
      format,
      width: 800,
      quality: 85
    }
  }
});

Workers 转换的优势:

  • 自定义 URL 方案:隐藏图片存储位置
  • 预设名称:使用 thumbnail、avatar、large 代替像素值
  • 内容协商:根据浏览器提供最合适的格式
  • 访问控制:提供图片前检查身份验证
  • 动态调整尺寸:根据设备类型计算尺寸

参见:templates/transform-via-workers.ts、references/transformation-options.md


变体管理

命名变体(最多 100 个)

为不同使用场景创建预定义转换。

通过 API 创建:

curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/variants" \
  --header "Authorization: Bearer <API_TOKEN>" \
  --header "Content-Type: application/json" \
  --data '{
    "id": "avatar",
    "options": {
      "fit": "cover",
      "width": 200,
      "height": 200,
      "metadata": "none"
    },
    "neverRequireSignedURLs": false
  }'

在 URL 中使用:

<img src="https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/avatar" />

适用场景:

  • 在应用中保持图片尺寸一致
  • 私有图片(可与签名 URL 配合使用)
  • 简单且可预测的 URL

参见:templates/variants-management.ts

灵活变体

使用 URL 中的参数进行动态转换。

启用(每个账户仅需一次):

curl --request PATCH \
  https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/config \
  --header "Authorization: Bearer <API_TOKEN>" \
  --header "Content-Type: application/json" \
  --data '{"flexible_variants": true}'

在 URL 中使用:

<img src="https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/w=400,sharpen=3" />

适用场景:

  • 需要动态调整尺寸
  • 仅适用于公开图片(不能与签名 URL 配合使用)
  • 快速原型设计

重要提示:

  • ❌ 不能与 requireSignedURLs=true 搭配使用
  • ✅ 私有图片请使用命名变体

参见:references/variants-guide.md

签名 URL(私有图片)

使用 HMAC-SHA256 令牌为私有图片生成有时效限制的 URL。

URL 格式:

https://imagedelivery.net/<ACCOUNT_HASH>/<IMAGE_ID>/<VARIANT>?exp=<EXPIRY>&sig=<SIGNATURE>

生成签名(Workers 示例):

async function generateSignedURL(
  imageId: string,
  variant: string,
  expirySeconds: number = 3600
): Promise<string> {
  const accountHash = 'YOUR_ACCOUNT_HASH';
  const signingKey = 'YOUR_SIGNING_KEY'; // Dashboard → Images → Keys

  const expiry = Math.floor(Date.now() / 1000) + expirySeconds;
  const stringToSign = `${imageId}${variant}${expiry}`;

  const encoder = new TextEncoder();
  const keyData = encoder.encode(signingKey);
  const messageData = encoder.encode(stringToSign);

  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    keyData,
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign']
  );

  const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData);
  const sig = Array.from(new Uint8Array(signature))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');

  return `https://imagedelivery.net/${accountHash}/${imageId}/${variant}?exp=${expiry}&sig=${sig}`;
}

用法:

const signedURL = await generateSignedURL('image-id', 'public', 3600);
// Returns URL valid for 1 hour

适用场景:

  • 用户个人资料照片(分享前为私有)
  • 付费内容(限时访问)
  • 临时下载
  • 安全的图片交付

参见:templates/signed-urls-generation.ts、references/signed-urls-guide.md


响应式图片

为不同屏幕尺寸提供最佳图片尺寸。

使用命名变体:

<img
  srcset="
    https://imagedelivery.net/<HASH>/<ID>/mobile 480w,
    https://imagedelivery.net/<HASH>/<ID>/tablet 768w,
    https://imagedelivery.net/<HASH>/<ID>/desktop 1920w
  "
  sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1920px"
  src="https://imagedelivery.net/<HASH>/<ID>/desktop"
  alt="Responsive image"
/>

使用灵活变体:

<img
  srcset="
    https://imagedelivery.net/<HASH>/<ID>/w=480,f=auto 480w,
    https://imagedelivery.net/<HASH>/<ID>/w=768,f=auto 768w,
    https://imagedelivery.net/<HASH>/<ID>/w=1920,f=auto 1920w
  "
  sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1920px"
  src="https://imagedelivery.net/<HASH>/<ID>/w=1920,f=auto"
  alt="Responsive image"
/>

艺术指导(移动设备与桌面设备使用不同裁剪方式):

<picture>
  <source
    media="(max-width: 767px)"
    srcset="https://imagedelivery.net/<HASH>/<ID>/mobile-square"
  />
  <source
    media="(min-width: 768px)"
    srcset="https://imagedelivery.net/<HASH>/<ID>/desktop-wide"
  />
  <img src="https://imagedelivery.net/<HASH>/<ID>/desktop-wide" alt="Hero image" />
</picture>

参见:templates/responsive-images-srcset.html、references/responsive-images-patterns.md


关键规则

务必遵循

✅ Direct Creator Upload 使用 multipart/form-data ✅ 将文件字段命名为 file(而不是 image 或其他名称) ✅ 仅从后端调用 /direct_upload API(不要从浏览器调用) ✅ 转换时使用 HTTPS URL(不支持 HTTP) ✅ 对图片路径中的特殊字符进行 URL 编码 ✅ 使用 /cdn-cgi/image/ 前,先在 zone 上启用转换 ✅ 私有图片使用命名变体(签名 URL) ✅ 检查 Cf-Resized 标头以确认是否存在转换错误 ✅ 设置 format=auto 以自动转换为 WebP/AVIF ✅ 使用 fit=scale-down 以防止不必要的放大

切勿执行

❌ 文件上传时使用 application/json Content-Type ❌ 从浏览器调用 /direct_upload(CORS 会失败) ❌ 在 requireSignedURLs=true 时使用灵活变体 ❌ 调整 SVG 文件大小(它们本身即可缩放) ❌ 转换时使用 HTTP URL(仅支持 HTTPS) ❌ 在 URL 中使用空格或未转义的 Unicode 字符 ❌ 在 Workers 中多次转换同一张图片(会导致 9403 循环) ❌ 图片大小超过 100 megapixels ❌ 在 Workers 中使用 /cdn-cgi/image/ 端点(改用 cf.image) ❌ 忘记在使用前于 zone 上启用转换


已知问题预防

此技能可预防 13+ 个已记录的问题。

问题 #1:Direct Creator Upload CORS 错误

错误:Access to XMLHttpRequest blocked by CORS policy: Request header field content-type is not allowed

来源:Cloudflare Community #345739、#368114

原因:服务器的 CORS 设置仅允许 Content-Type 标头使用 multipart/form-data

预防措施:

// ✅ CORRECT
const formData = new FormData();
formData.append('file', fileInput.files[0]);
await fetch(uploadURL, {
  method: 'POST',
  body: formData // Browser sets multipart/form-data automatically
});

// ❌ WRONG
await fetch(uploadURL, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' }, // CORS error
  body: JSON.stringify({ file: base64Image })
});
问题 #2:错误 5408 - 上传超时

错误:上传约 15 秒后出现 Error 5408

来源:Cloudflare Community #571336

原因:Cloudflare 的请求超时时间为 30 秒;上传速度慢或文件过大都会超出限制

预防措施:

  • 上传前压缩图片(使用 Canvas API 在客户端压缩)
  • 设置合理的文件大小限制(例如,最大 10MB)
  • 向用户显示上传进度
  • 妥善处理超时错误
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB

if (file.size > MAX_FILE_SIZE) {
  alert('File too large. Please select an image under 10MB.');
  return;
}
问题 #3:错误 400 - 文件参数无效

错误:400 Bad Request,且错误消息没有提供有用信息

来源:Cloudflare Community #487629

原因:文件字段必须命名为 file(而不是 image、photo 等)

预防措施:

// ✅ CORRECT
formData.append('file', imageFile);

// ❌ WRONG
formData.append('image', imageFile); // 400 error
formData.append('photo', imageFile); // 400 error
问题 #4:CORS 预检失败

错误:预检 OPTIONS 请求被阻止

来源:Cloudflare Community #306805

原因:直接从浏览器调用 /direct_upload API(该操作应仅在后端进行)

预防措施:

ARCHITECTURE:
Browser → Backend API → POST /direct_upload → Returns uploadURL → Browser uploads to uploadURL

切勿向浏览器公开 API 令牌。在后端生成上传 URL,再返回给前端。

问题 #5:错误 9401 - 参数无效

错误:Cf-Resized: err=9401 - 必需的 cf.image 选项缺失或无效

来源:Cloudflare Images 文档 - 故障排除

原因:缺少必需的转换参数或参数值无效

预防:

// ✅ CORRECT
fetch(imageURL, {
  cf: {
    image: {
      width: 800,
      quality: 85,
      format: 'auto'
    }
  }
});

// ❌ WRONG
fetch(imageURL, {
  cf: {
    image: {
      width: 'large', // Must be number
      quality: 150 // Max 100
    }
  }
});
问题 #6:错误 9402 - 图像过大

错误:Cf-Resized: err=9402 - 图像过大或连接中断

来源:Cloudflare Images 文档 - 故障排除

原因:图像超过最大面积(100 百万像素)或下载失败

预防:

  • 转换前验证图像尺寸
  • 使用尺寸合理的源图像(最大 10000x10000px)
  • 妥善处理网络错误
问题 #7:错误 9403 - 请求循环

错误:Cf-Resized: err=9403 - Worker 正在获取自己的 URL 或已调整尺寸的图像

来源:Cloudflare Images 文档 - 故障排除

原因:对已转换的图像再次应用转换,或 Worker 获取自身

预防:

// ✅ CORRECT
if (url.pathname.startsWith('/images/')) {
  const originalPath = url.pathname.replace('/images/', '');
  const originURL = `https://storage.example.com/${originalPath}`;
  return fetch(originURL, { cf: { image: { width: 800 } } });
}

// ❌ WRONG
if (url.pathname.startsWith('/images/')) {
  // Fetches worker's own URL, causes loop
  return fetch(request, { cf: { image: { width: 800 } } });
}
问题 #8:错误 9406/9419 - URL 格式无效

错误:Cf-Resized: err=9406 或 err=9419 - URL 不是 HTTPS,或 URL 中包含空格/未转义的 Unicode 字符

来源:Cloudflare Images 文档 - 故障排除

原因:图像 URL 使用 HTTP(而非 HTTPS)或包含无效字符

预防:

// ✅ CORRECT
const imageURL = "https://example.com/images/photo%20name.jpg";

// ❌ WRONG
const imageURL = "http://example.com/images/photo.jpg"; // HTTP not allowed
const imageURL = "https://example.com/images/photo name.jpg"; // Space not encoded

URL 路径务必使用 encodeURIComponent():

const filename = "photo name.jpg";
const imageURL = `https://example.com/images/${encodeURIComponent(filename)}`;
问题 #9:错误 9412 - 响应不是图像

错误:Cf-Resized: err=9412 - 源站返回了 HTML,而非图像

来源:Cloudflare Images 文档 - 故障排除

原因:源站服务器返回了 404 页面或错误页面(HTML),而非图像

预防:

// Verify URL before transforming
const originResponse = await fetch(imageURL, { method: 'HEAD' });
const contentType = originResponse.headers.get('content-type');

if (!contentType?.startsWith('image/')) {
  return new Response('Not an image', { status: 400 });
}

return fetch(imageURL, { cf: { image: { width: 800 } } });
问题 #10:超过图像最大面积限制(错误 9413)

错误:Cf-Resized: err=9413 - 图像超过 100 百万像素

来源:Cloudflare Images 文档 - 故障排除

原因:源图像尺寸超过 100 百万像素(例如,10000x10000px)

预防:

  • 上传前验证图像尺寸
  • 预处理过大的图像
  • 拒绝超过阈值的图像
const MAX_MEGAPIXELS = 100;

if (width * height > MAX_MEGAPIXELS * 1_000_000) {
  return new Response('Image too large', { status: 413 });
}
问题 #11:灵活变体与签名 URL 不兼容

错误:灵活变体无法用于私有图像

来源:Cloudflare Images 文档 - 启用灵活变体

原因:requireSignedURLs=true 时无法使用灵活变体

预防:

// ✅ CORRECT - Use named variants for private images
await uploadImage({
  file: imageFile,
  requireSignedURLs: true // Use named variants: /public, /avatar, etc.
});

// ❌ WRONG - Flexible variants don't support signed URLs
// Cannot use: /w=400,sharpen=3 with requireSignedURLs=true
问题 #12:SVG 缩放限制

错误:无法通过转换调整 SVG 文件的尺寸

来源:Cloudflare Images 文档 - SVG 文件

原因:SVG 本身可缩放(矢量格式),不适用尺寸调整

预防:

// SVGs can be served but not resized
// Use any variant name as placeholder
// https://imagedelivery.net/<HASH>/<SVG_ID>/public

// SVG will be served at original size regardless of variant settings
问题 #13:默认会剥除 EXIF 元数据

错误:上传的 JPEG 中的 GPS 数据和相机设置被移除

来源:Cloudflare Images 文档 - 通过 URL 转换

原因:默认行为会剥除所有元数据,版权信息除外

预防:

// Preserve metadata
fetch(imageURL, {
  cf: {
    image: {
      width: 800,
      metadata: 'keep' // Options: 'none', 'copyright', 'keep'
    }
  }
});

选项:

  • none:剥除所有元数据
  • copyright:仅保留版权标签(JPEG 默认值)
  • keep:保留大部分 EXIF 元数据,包括 GPS

使用捆绑资源

模板(templates/)

可直接复制粘贴的常见模式代码:

  1. wrangler-images-binding.jsonc - Wrangler 配置(无需绑定)
  2. upload-api-basic.ts - 将文件上传到 Images API
  3. upload-via-url.ts - 从外部 URL 导入图像
  4. direct-creator-upload-backend.ts - 生成一次性上传 URL
  5. direct-creator-upload-frontend.html - 用户上传表单
  6. transform-via-url.ts - URL 转换示例
  7. transform-via-workers.ts - Workers 转换模式
  8. variants-management.ts - 创建、列出和删除变体
  9. signed-urls-generation.ts - HMAC-SHA256 签名 URL 生成
  10. responsive-images-srcset.html - 响应式图像模式
  11. batch-upload.ts - 面向高容量上传的 Batch API

用法:

cp templates/upload-api-basic.ts src/upload.ts
# Edit with your account ID and API token
参考资料(references/)

Claude 可按需加载的深入文档:

  1. api-reference.md - 完整的 API 端点(上传、列出、删除、变体)
  2. transformation-options.md - 所有转换参数及示例
  3. variants-guide.md - 命名变体与灵活变体,以及各自的适用场景
  4. signed-urls-guide.md - HMAC-SHA256 实现细节
  5. direct-upload-complete-workflow.md - 完整架构和流程
  6. responsive-images-patterns.md - srcset、sizes、艺术指导
  7. format-optimization.md - WebP/AVIF 自动转换策略
  8. top-errors.md - 13 种以上错误及详细故障排查说明

加载时机:

  • 深入了解特定功能
  • 排查复杂问题
  • 了解 API 详情
  • 实现高级模式
脚本(scripts/)

check-versions.sh - 验证 API 端点是否为最新版本


高级主题

自定义域名

使用您自己的域名提供图像,而不是使用 imagedelivery.net。

URL 格式:

https://example.com/cdn-cgi/imagedelivery/<ACCOUNT_HASH>/<IMAGE_ID>/<VARIANT>

要求:

  • 域名必须托管在 Cloudflare 上(与 Images 属于同一账户)
  • 必须通过 Cloudflare 代理(橙色云朵)

自定义路径(转换规则):

将 /images/... 重写为 /cdn-cgi/imagedelivery/...:

  1. Dashboard → Rules → Transform Rules → Rewrite URL
  2. 匹配:starts_with(http.request.uri.path, "/images/")
  3. 重写:/cdn-cgi/imagedelivery/<ACCOUNT_HASH>${substring(http.request.uri.path, 7)}

现在,/images/{id}/{variant} → /cdn-cgi/imagedelivery/{hash}/{id}/{variant}

参见:通过自定义域名提供图像

Batch API

使用 Batch Token 进行高容量上传。

主机:batch.imagedelivery.net(而非 api.cloudflare.com)

用法:

# Create batch token in dashboard: Images → Batch API

curl "https://batch.imagedelivery.net/images/v1" \
  --header "Authorization: Bearer <BATCH_TOKEN>" \
  --form 'file=@./image.jpg'

适用场景:

  • 迁移数千张图像
  • 批量上传工作流
  • 自动导入图像

参见:templates/batch-upload.ts

Webhook

接收上传成功或失败的通知(仅限 Direct Creator Upload)。

设置:

  1. Dashboard → Notifications → Destinations → Webhooks → Create
  2. 输入 Webhook URL 并进行测试
  3. Notifications → All Notifications → Add → Images → Select webhook

Payload(示例):

{
  "imageId": "2cdc28f0-017a-49c4-9ed7-87056c83901",
  "status": "uploaded",
  "metadata": {"userId": "12345"}
}

适用场景:

  • 上传后更新数据库
  • 触发图像处理流水线
  • 通知用户上传状态

参见:配置 Webhook


故障排查

问题:图像未转换

症状:/cdn-cgi/image/... 返回原始图像或 404

解决方案:

  1. 在区域上启用转换:Dashboard → Images → Transformations → Enable for zone
  2. 确认区域已通过 Cloudflare 代理(橙色云朵)
  3. 检查源图像是否可公开访问
  4. 等待 5–10 分钟,让设置生效
问题:直接上传返回 CORS 错误

症状:浏览器控制台中出现 Access-Control-Allow-Origin 错误

解决方案:

  1. 使用 multipart/form-data 编码(让浏览器设置 Content-Type)
  2. 不要从浏览器调用 /direct_upload;应从后端调用
  3. 将文件字段命名为 file(而不是 image)
  4. 移除手动设置的 Content-Type 标头
问题:Worker 转换返回 9403 循环错误

症状:响应标头中出现 Cf-Resized: err=9403

解决方案:

  1. 不要获取 Worker 自身的 URL(请使用外部源站)
  2. 不要转换已经调整过大小的图片
  3. 检查 URL 路由逻辑,避免循环
问题:签名 URL 无法使用

症状:访问签名 URL 时出现 403 Forbidden

解决方案:

  1. 确认上传图片时使用了 requireSignedURLs=true
  2. 检查签名生成方式(HMAC-SHA256)
  3. 确保过期时间戳在未来
  4. 确认签名密钥与控制面板中的密钥一致(Images → Keys)
  5. 签名 URL 不能使用灵活变体(请使用命名变体)
问题:图片已上传但未显示

症状:上传返回 200 OK,但图片未显示在控制面板中

解决方案:

  1. 检查响应中是否包含 draft: true(Direct Creator Upload)
  2. 等待上传完成(通过 GET /images/v1/{id} 检查)
  3. 确认账户 ID 匹配
  4. 检查 Webhook 中是否有上传错误

完整设置清单

  • 已启用 Images 的 Cloudflare 账户
  • 已获取账户 ID 和 API 令牌(Images: Edit 权限)
  • [ ](可选)已在区域上启用图片转换
  • [ ](可选)已为常见用例创建变体
  • [ ](可选)如需动态调整大小,已启用灵活变体
  • [ ](可选)已获取私有图片的签名密钥
  • [ ](可选)已配置上传通知的 Webhook
  • [ ](可选)已通过 Transform Rules 配置自定义域名
  • 已实现上传方式(文件、URL 或直接创建者上传)
  • 已测试服务 URL(imagedelivery.net 或自定义域名)
  • 已测试转换(URL 或 Workers)
  • 已实现错误处理(CORS、超时、大小限制)

官方文档


软件包版本(已于 2025-10-26 验证)

API 版本:v2(用于直接上传),v1(用于标准上传)

无需 npm 软件包——使用原生 Cloudflare API

可选:

  • @cloudflare/workers-types@latest——Workers 的 TypeScript 类型

有问题?遇到故障?

  1. 查看 references/top-errors.md 了解常见问题
  2. 确认设置流程中的所有步骤均已完成
  3. 查看官方文档:https://developers.cloudflare.com/images/
  4. 确认已在区域上启用转换
  5. 确认 Direct Creator Upload 的 CORS 设置

评论

支持 Markdown