1942 字
10 分鐘

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、轉檔或 drawenv.IMAGES.input()
由 Worker 管理 Cloudflare Images 裡的 hosted imagesenv.IMAGES.hosted
把文字變成可 draw 的影像圖層env.IMAGES.text()
讓瀏覽器直接上傳而不暴露 API tokenenv.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 行為:

Terminal window
# offline、低 fidelity;目前支援 width、height、rotate、format
pnpm 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。

建議至少測三條路徑:

  1. input → transform → output 的基本轉檔。
  2. hosted.list 的 metadata filter,包含成功、欄位拼錯和超過五個 conditions 的失敗。
  3. 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

Cloudflare Docs:Optimize with Workers

Cloudflare Docs:Manage hosted images with Workers

Cloudflare Images binding:text、signedUrl 與 metadata filter
https://laplusda.com/posts/cloudflare-images-binding-updates/
作者
Zero
發佈於
2026-09-03
許可協議
CC BY-NC-SA 4.0
這篇文章有幫助嗎?

回報錯字、失效連結,或告訴我你想看的延伸主題。