Cloudflare Image Optimization: Polish, Image Resizing, và Workers - tối ưu ảnh không cần thay đổi code

Ảnh thường chiếm 60–80% tổng bytes của một web page. Cloudflare có 3 tầng tối ưu ảnh: **Polish** (nén tự động, không cần code), **Image Resizing** (resize theo URL params, Pro plan), và **Transform via Workers** (full control, dùng Workers). Bài này hướng dẫn cả ba - từ setup nhanh nhất đến pipeline on-the-fly linh hoạt nhất. ---

Vấn đề

Tình huống quen thuộc: designer export ảnh banner 3000×2000px, 2.5MB. Đưa lên web không xử lý. User mobile tải nguyên file đó để hiển thị trong container 375px width. Lãng phí bandwidth, chậm load, trải nghiệm kém - trong khi ảnh đúng chuẩn chỉ cần 80KB.

Giải pháp truyền thống: setup ImageMagick/Sharp trên server, viết pipeline resize, lưu nhiều kích thước. Cloudflare làm điều này ở edge - không cần server, không cần code xử lý ảnh, không cần lưu nhiều phiên bản.


3 tầng image optimization của Cloudflare

Tầng 1: Polish          → Nén tự động (free plan: lossless, Pro: lossy + WebP)
Tầng 2: Image Resizing  → Resize theo URL params (Pro plan)
Tầng 3: Workers Transform → Full pipeline qua Workers (Pro plan)

Tùy nhu cầu, bạn dùng một hoặc kết hợp cả ba.


Tầng 1: Polish - nén ảnh tự động, không cần code (Free + Pro)

Polish là tính năng đơn giản nhất: Cloudflare tự động nén và tối ưu ảnh khi serve từ cache, không cần thay đổi gì trong code hay markup.

Bật Polish

Vào Speed → Optimization → Image Optimization → Polish.

Có 3 chế độ:

Chế độ Mô tả Plan
Off Không làm gì All
Lossless Nén không mất chất lượng, xóa metadata (EXIF) Free
Lossy Nén có mất chất lượng nhẹ, convert WebP Pro

Kết quả thực tế:

  • Lossless: giảm trung bình ~21% file size
  • Lossy: giảm 30–50%, đặc biệt hiệu quả với JPEG
  • WebP (Lossy): PNG giảm ~26%, JPEG giảm ~17% so với không WebP

Bật WebP (kèm theo Lossy)

Vào Speed → Optimization → Image Optimization → Polish → bật thêm toggle WebP.

Khi WebP được bật, Cloudflare phục vụ WebP cho browser hỗ trợ (gần như tất cả browser hiện đại), giữ JPEG/PNG cho browser cũ - tự động dựa trên Accept header.

Request (Chrome): Accept: image/webp,image/apng,...
→ Cloudflare serve: image.webp

Request (IE11): Accept: image/jpeg,...
→ Cloudflare serve: image.jpg (original)

Không cần thay đổi HTML hay tag - Cloudflare xử lý hoàn toàn transparent.

Lưu ý quan trọng với Polish

  • Polish chỉ áp dụng cho ảnh được cache ở Cloudflare (proxy ON). Nếu Cache-Control là no-store, Polish không chạy.
  • Polish không áp dụng cho ảnh đã được transform qua Image Resizing - resized images đã được tối ưu riêng.
  • Polish áp dụng cho: JPEG, PNG, GIF, WebP nguồn. Không áp dụng: SVG, animated GIF phức tạp.
  • Verify Polish đang hoạt động: xem response header cf-polished trên ảnh.
curl -I https://yourdomain.com/images/banner.jpg | grep cf-polished
# cf-polished: qual=85, origFmt=jpeg, origSize=245678

Tầng 2: Image Resizing - resize on-the-fly qua URL (Pro plan)

Image Resizing cho phép resize, crop, convert format ảnh bằng cách thêm params vào URL - không cần lưu nhiều phiên bản trên server.

Cú pháp URL

https://yourdomain.com/cdn-cgi/image/<options>/<original-url>

Ví dụ:

# Resize width 800px, giữ ratio, convert WebP
https://example.com/cdn-cgi/image/width=800,format=webp/uploads/banner.jpg

# Resize 400x300, crop giữa
https://example.com/cdn-cgi/image/width=400,height=300,fit=crop/uploads/product.jpg

# Chất lượng 80%, nén
https://example.com/cdn-cgi/image/quality=80,format=auto/uploads/photo.jpg

Các options phổ biến

Option Mô tả Ví dụ
width Chiều rộng (px) width=800
height Chiều cao (px) height=600
fit Cách fit: scale-down, contain, cover, crop, pad fit=cover
quality Chất lượng 1-100 quality=85
format Output format: webp, avif, jpeg, png, auto format=auto
dpr Device pixel ratio (retina) dpr=2
blur Blur ảnh (1-250) blur=10
sharpen Tăng độ sắc nét (0-10) sharpen=2
gravity Điểm neo khi crop: auto, left, right, top, bottom, face gravity=auto

format=auto tự động chọn WebP hoặc AVIF nếu browser hỗ trợ - khuyến nghị dùng mặc định.

Dùng với srcset (responsive images)

<img
  src="/cdn-cgi/image/width=800,format=auto/uploads/hero.jpg"
  srcset="
    /cdn-cgi/image/width=400,format=auto/uploads/hero.jpg 400w,
    /cdn-cgi/image/width=800,format=auto/uploads/hero.jpg 800w,
    /cdn-cgi/image/width=1200,format=auto/uploads/hero.jpg 1200w
  "
  sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
  alt="Hero banner"
  loading="lazy"
/>

Browser tự chọn kích thước phù hợp với viewport và pixel density - không cần JavaScript.


Tầng 3: Transform qua Workers - full control (Pro plan)

Nếu cần logic phức tạp hơn (thêm watermark, dynamic crop dựa trên content, A/B test format), dùng Workers để gọi Image Resizing API:

// Worker: image-optimizer.ts
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);

    // Chỉ xử lý path /img/*
    if (!url.pathname.startsWith("/img/")) {
      return fetch(request);
    }

    // Lấy original image từ R2 hoặc origin
    const originalPath = url.pathname.replace("/img/", "/originals/");
    const originalUrl = `https://${url.hostname}${originalPath}`;

    // Parse resize params từ query string
    const width = parseInt(url.searchParams.get("w") ?? "800");
    const quality = parseInt(url.searchParams.get("q") ?? "85");
    const format = url.searchParams.get("fmt") ?? "auto";

    // Gọi Image Resizing API của Cloudflare
    const response = await fetch(originalUrl, {
      cf: {
        image: {
          width,
          quality,
          format,
          fit: "scale-down",
          metadata: "none", // xóa EXIF
        },
      },
    });

    if (!response.ok) {
      return new Response("Image not found", { status: 404 });
    }

    // Cache kết quả 30 ngày
    const optimizedResponse = new Response(response.body, response);
    optimizedResponse.headers.set("Cache-Control", "public, max-age=2592000");
    optimizedResponse.headers.set("Vary", "Accept");

    return optimizedResponse;
  },
};

URL dùng với Worker này:

https://example.com/img/uploads/product.jpg?w=400&q=80&fmt=webp

Tích hợp R2 + Image Resizing

Pattern phổ biến: lưu ảnh gốc trên R2, serve ảnh đã optimize qua Workers:

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    const key = url.pathname.slice(1); // "/products/abc.jpg" → "products/abc.jpg"

    // Lấy từ R2
    const object = await env.IMAGES_BUCKET.get(key);
    if (!object) return new Response("Not found", { status: 404 });

    // Chuyển R2 object thành URL để Cloudflare Image Resizing xử lý
    // (Dùng R2 public URL hoặc presigned URL)
    const r2Url = `https://assets.example.com/${key}`;

    const width = parseInt(url.searchParams.get("w") ?? "0") || undefined;
    const format = url.searchParams.get("fmt") as "webp" | "avif" | "auto" ?? "auto";

    return fetch(r2Url, {
      cf: {
        image: { width, format, quality: 85, fit: "scale-down" },
      },
    });
  },
};

So sánh 3 phương án

Polish Image Resizing Workers Transform
Plan Free (lossless) / Pro (lossy+WebP) Pro Pro
Cần code? Không Không (URL params) Có (Worker)
Flexibility Thấp Trung bình Cao
Dùng khi Site không muốn thay đổi code Cần nhiều kích thước Logic phức tạp
Format output WebP tự động WebP, AVIF, auto WebP, AVIF, auto
Retina/DPR Không Có (dpr=2)
Cache Theo Cache-Control 1 giờ + Tùy cấu hình

Best practices tổng hợp

1. Luôn dùng format=auto thay vì chỉ định WebP cứng - Cloudflare tự serve AVIF (nhỏ hơn WebP 30%) cho browser hỗ trợ.

2. Đặt loading="lazy" trên ảnh below the fold - giảm LCP time, không liên quan đến Cloudflare nhưng pair tốt.

3. Xóa EXIF metadata (metadata: "none" trong Workers hoặc Polish làm tự động) - giảm file size, bảo vệ privacy.

4. Lưu ảnh gốc resolution cao nhất trên R2, serve nhiều kích thước qua Image Resizing - không cần lưu nhiều phiên bản.

5. Cache ảnh đã transform lâu (Cache-Control: public, max-age=2592000) - nội dung đã hash trong URL không bao giờ stale.

6. Verify với Lighthouse - sau khi setup, chạy PageSpeed Insights để xem điểm "Serve images in next-gen formats" và "Properly size images" có pass không.


Kết

Cloudflare Image Optimization là một trong những quick win dễ implement nhất để cải thiện performance web - đặc biệt Polish, chỉ cần một click bật là giảm ngay 20–50% dung lượng ảnh. Với site Pro plan, Image Resizing cho phép xây dựng responsive image pipeline hoàn chỉnh mà không cần server riêng để xử lý ảnh.

Kết hợp với Cache RulesR2 Storage, bạn có một pipeline phân phối ảnh hoàn chỉnh ở edge - nhanh, rẻ, không egress fee.


Tham khảo


BKGlobal Tech Team

Blog Công nghệ

Xem tất cả