Cloudflare Images binding:text、signedUrl 與 metadata filter
Cloudflare Images binding 在 2026 年 9 月 2 日迎來一批實用更新:最佳化流程新增文字 rasterize;Hosted images 可以依自訂 metadata 篩選、產生 private signed URL,也能建立 Direct Creator Upload URL。這些能力都從 Worker 的 env.IMAGES 進入,但用途其實分成兩條路:
| 需求 | 使用方式 |
|---|---|
| 對任何 raw image bytes 做 resize、轉檔或 draw | env.IMAGES.input() |
| 由 Worker 管理 Cloudflare Images 裡的 hosted images | env.IMAGES.hosted |
| 把文字變成可 draw 的影像圖層 | env.IMAGES.text() |
| 讓瀏覽器直接上傳而不暴露 API token | env.IMAGES.hosted.createDirectUpload() |
先分清楚這兩條路,會比把 Images binding 當成另一個「只能拿 URL 做轉換」的 API 更容易設計。Optimization binding 可以接收 fetch response、R2、Images 或 request body 的 bytes;Hosted namespace 則負責上傳、列出、讀取、更新和刪除帳戶內的圖片。
先把 IMAGES binding 綁到 Worker
在 Worker 專案的 Wrangler 設定檔加入:
{ "images": { "binding": "IMAGES" }}如果使用 TOML:
[images]binding = "IMAGES"設定完成後,Worker 程式就能使用 env.IMAGES。這個 binding 是以 Worker 為單位啟用;也可以在 Cloudflare Dashboard 的 Worker 設定中配置。
如果會服務大量重複的轉換結果,建議同時啟用 Workers Cache:
{ "images": { "binding": "IMAGES" }, "cache": { "enabled": true }}Images binding 的 response 不會自動 cache;每次未快取的 request 都可能重新 decode 和 encode。Cloudflare 建議搭配 Cache-Control,讓 Worker 不必對相同的來源與參數反覆處理。
用 input 直接轉換 fetch 或 R2 的 bytes
input(stream) 接受最多 20 MB 的影像 bytes,可以來自 fetch response、request body、R2 或 hosted image。最小的 Worker 流程如下:
export default { async fetch(request, env) { const imageURL = "https://example.com/photo.jpg"; const upstream = await fetch(imageURL);
if (!upstream.ok || !upstream.body) { return new Response("Upstream fetch failed", { status: 502 }); }
const output = await env.IMAGES .input(upstream.body) .transform({ width: 800 }) .output({ format: "image/webp" });
return output.response({ headers: { "Cache-Control": "public, max-age=3600, stale-while-revalidate=86400" } }); }};這個 chain 的順序是 input → transform → output。output() 必須指定輸出 format;若需要調整操作順序,可以串多個 transform 或加入 draw。Content-Type 會依 output format 設定,不能在 response options 中覆寫;Cache-Control 則可以透過 response 的 headers 傳入。
實際上線時不要直接接受任意 query string 的來源 URL。應先做 origin allowlist、檔案大小檢查和 content type 驗證,避免把 Worker 變成任意 URL 代理或無限制的圖片轉換端點。
用 text 建立可疊加的影像圖層
text(content, options) 會把文字 rasterize 成影像,回傳的 handle 可以直接 output 成透明背景圖片,也可以交給 draw 疊到 base image 上。文字上限是 1,000 個字元,產生的圖片最多 4096 × 4096;自訂字型 URL 上限為 20 MB。
概念上可以這樣組合:
const label = env.IMAGES.text("Preview", { color: "#ffffff", size: 28});
const output = await env.IMAGES .input(imageStream) .draw(label, { opacity: 0.9 }) .output({ format: "image/webp" });
return output.response();text() 的 styling options 也適用於 draw array 中的 text entry。若是 production watermark,應再處理字型來源的可用性、文字內容的 escaping 和輸出快取,不要把每個使用者輸入直接當成可信的固定標籤。
Hosted namespace:上傳、列出與管理圖片
若圖片是存放在 Cloudflare Images 帳戶內,使用 env.IMAGES.hosted。例如從 request body 上傳並附加 metadata:
export default { async fetch(request, env) { if (!request.body) { return new Response("Missing body", { status: 400 }); }
const image = await env.IMAGES.hosted.upload(request.body, { filename: "upload.jpg", metadata: { source: "worker", status: "active" }, requireSignedURLs: false });
return Response.json(image); }};Hosted image 的管理操作需要付費 Images plan with storage,費用和帳戶中使用 REST API 或 Dashboard 的操作相同。若只是把已取得的 raw bytes 做轉換,則要另外看 optimization binding 的 unique transformation 計費規則;同一個月內相同來源與參數組合重複呼叫不會再次增加 usage,info() 則是免費操作。
用 metadata filter 找出可用圖片
更新後的 list() 可以在 filter.metadata 使用自訂 metadata。多個欄位是 AND 關係,同一欄位也可以合併 range:
export default { async fetch(request, env) { const { images } = await env.IMAGES.hosted.list({ filter: { metadata: { status: "active", priority: { gte: 2, lte: 5 } } } });
return Response.json(images.map((image) => image.id)); }};要留意幾個限制:
- metadata field name 只能包含英文字母、數字、底線和句點;含有連字號或空白的欄位不能用來 filter。
- nested field 可以用句點表示,最多五層。
- in 陣列最多 10 個值,單一 list request 最多五個 conditions;同一個 range 的 gte 和 lte 會各算一個 condition。
- 不支援的欄位、operator 或超過條件上限時,request 會失敗,不會退回未篩選的完整清單。
最後一點很重要:metadata filter 的失敗是 fail closed,而不是悄悄把所有圖片回傳。應在 endpoint 中處理錯誤,並替管理畫面記錄實際採用的 field name 和 operator。
Private image 用 signed URL 讓瀏覽器直取
如果 hosted image 設定為需要 signed URL,Worker 可以產生短效 delivery URL,再 redirect 瀏覽器:
export default { async fetch(request, env) { const url = await env.IMAGES.hosted .image("IMAGE_ID") .signedUrl({ variant: "private", expiresIn: 86400 });
return Response.redirect(url, 302); }};signed URL 由 Cloudflare 端簽署,Worker 不需要處理帳戶 signing key,也不必代替瀏覽器串流原始 bytes。expiresIn 應依實際下載或檢視情境設定;不要把長效 URL 當成私有資產的永久授權。
Direct Creator Upload 避免 token 經過瀏覽器
使用者上傳時,後端可以先建立 Direct Creator Upload URL,再把 URL 和 image ID 傳給前端:
export default { async fetch(request, env) { const { id, uploadURL } = await env.IMAGES.hosted.createDirectUpload({ metadata: { source: "profile" }, requireSignedURLs: true, expiresIn: 600 });
return Response.json({ id, uploadURL }); }};expiresIn 必須介於 120 和 21600 秒,預設是 1800 秒。這種流程讓 client 直接把圖片傳到 Cloudflare,不必把 API token 暴露給瀏覽器,也不用讓 Worker 處理整個 upload body;但建立 upload URL 的 endpoint 仍要有自己的登入、配額、檔案類型和 abuse controls。
local 與 remote Wrangler 測試不是同一種覆蓋率
Cloudflare 提供兩種 local development 行為:
# offline、低 fidelity;目前支援 width、height、rotate、formatpnpm exec wrangler dev
# remote、高 fidelity;會使用 Cloudflare 的 Images API 實作pnpm exec wrangler dev --remote兩者都不會因為 local development 本身產生 Images usage charges,但覆蓋率不同。offline 版本目前只支援 width、height、rotate 和 format;text()、完整 draw、hosted image 管理與其他新能力,應使用 —remote 或在部署前用 integration environment 驗證。Vitest integration 預設也會使用 offline 版本,以避免測試直接呼叫 Cloudflare API。
建議至少測三條路徑:
- input → transform → output 的基本轉檔。
- hosted.list 的 metadata filter,包含成功、欄位拼錯和超過五個 conditions 的失敗。
- private signed URL 與 Direct Creator Upload 的權限、過期和未授權結果。
結論:用 namespace 選擇正確的影像責任
這次 binding 更新的重點不是多幾個孤立方法,而是讓 Worker 能在同一份 binding 中處理影像轉換與 hosted asset 管理。env.IMAGES.input() 適合 raw bytes 的最佳化,env.IMAGES.hosted 適合帳戶內圖片的生命週期,text() 和 draw() 則負責組合影像內容。上線前補上 Cache-Control、來源 allowlist、metadata filter 的錯誤處理,以及 local/remote fidelity 的差異,就能避免把 demo chain 直接當成 production image service。
若你的站台仍以 R2 儲存原始圖片,可以先閱讀 Cloudflare R2 圖片託管與快取設定,再決定哪些內容適合留在 R2、哪些需要 Images 的 hosted 管理或 transformation。
常見問題
Q: Images binding 的 input 和 hosted 是同一件事嗎?
A: 不是。input 先接 raw image bytes,再串 transform、draw 和 output;hosted 則管理 Cloudflare Images 帳戶內的圖片。hosted image 的 bytes 可以再交給 input 做轉換,但兩者的責任和計費路徑要分開看。
Q: response() 可以改 Content-Type 嗎?
A: 不可以。Cloudflare 會依 output format 設定 Content-Type,response options 不能覆寫它;你可以透過 headers 設定 Cache-Control 等其他 response header。
Q: offline wrangler dev 測得到 text 和 metadata filter 嗎?
A: 不應假設可以。官方目前列出的 offline 支援集中在 width、height、rotate 和 format;完整 Images API 和 hosted 管理應用 wrangler dev —remote 或 integration environment 驗證。
參考資料:
Cloudflare Changelog:Images binding updates
回報錯字、失效連結,或告訴我你想看的延伸主題。