DDevArchive
Đăng nhập

Upload file & CDN: S3, pre-signed URL, image optimization

Avatar, hình sản phẩm, tài liệu PDF — hầu hết app cần upload file. Nhưng lưu file ở đâu? Làm sao upload nhanh? Ảnh 5MB user chờ loading mãi? Bài này dạy đầy đủ: S3/R2, pre-signed URL, resize ảnh, CDN.

Kiến trúc upload chuẩn

KHÔNG upload file qua server backend → server bị bottleneck. Thay vào đó: client upload trực tiếp lên S3 bằng pre-signed URL. Server chỉ tạo URL cho phép upload.

// File: presigned.ts
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'

const s3 = new S3Client({ region: "ap-southeast-1" })

// API: tạo pre-signed URL để client upload trực tiếp
async function getUploadUrl(req: Request, res: Response) {
  const key = `uploads/${req.user.id}/${Date.now()}-${req.body.filename}`

  const command = new PutObjectCommand({
    Bucket: process.env.S3_BUCKET,
    Key: key,
    ContentType: req.body.contentType,
  })

  const uploadUrl = await getSignedUrl(s3, command, {
    expiresIn: 300, // URL hết hạn sau 5 phút
  })

  res.json({ uploadUrl, key })
}

// Client: upload trực tiếp lên S3 (không qua server)
// await fetch(uploadUrl, { method: "PUT", body: file })

Image optimization: không ai chờ ảnh 5MB

Kỹ thuậtGiảm dung lượngCách dùng
WebP format25-35%Convert bằng sharp library hoặc CDN auto
Resize theo viewport50-80%Tạo nhiều size: thumbnail, medium, large
Lazy loadingKhông load ảnh ngoài viewportloading=“lazy” attribute
CDN (Cloudflare)Cache gần user, load nhanhTrỏ domain qua Cloudflare
💡 Cloudflare R2 > S3

Cloudflare R2 = S3-compatible nhưng KHÔNG TỐN PHÍ bandwidth (egress). S3 tính tiền mỗi lần user xem ảnh. R2 miễn phí egress → tiết kiệm 80%+ cho app có nhiều hình.

❓ Vì sao dùng pre-signed URL thay vì upload qua backend server?

  • Tạo pre-signed URL cho S3/R2
  • Client upload trực tiếp bằng pre-signed URL
  • Resize ảnh và convert WebP
  • Setup CDN (Cloudflare) cho static assets