DevToolBoxGRATIS
Blog

AWS S3 voor Ontwikkelaars: Upload, Voorgetekende URLs, Bucketbeleid en CloudFront

13 minby DevToolBox

Amazon S3 is de ruggengraat van bestandsopslag voor miljoenen applicaties. Deze gids behandelt de S3 SDK, presigned URLs, bucket-beleid en integratie met CloudFront.

S3-basisprincipes: buckets en objecten

S3 slaat gegevens op als objecten in buckets.

S3 Core Concepts:
  Bucket     β€” Top-level container (globally unique name, tied to a region)
  Object     β€” A file stored in a bucket (up to 5TB per object)
  Key        β€” The object's path/name: "uploads/2026/user-123/photo.jpg"
  Prefix     β€” Virtual folder: "uploads/2026/" (S3 has no real folders)
  Region     β€” Where the bucket lives: us-east-1, eu-west-1, ap-southeast-1

Storage Classes:
  Standard              β€” Frequently accessed data, 99.99% availability
  Standard-IA           β€” Infrequent access, lower cost, retrieval fee
  One Zone-IA           β€” Lower cost, single AZ (no cross-AZ replication)
  Intelligent-Tiering   β€” Auto-move between tiers based on access patterns
  Glacier Instant       β€” Archive with millisecond retrieval
  Glacier Flexible      β€” Archive with minutes-to-hours retrieval
  Glacier Deep Archive  β€” Cheapest storage, 12-48h retrieval

Bestanden uploaden met AWS SDK v3

De AWS SDK v3 gebruikt een modulair ontwerp om de bundelgrootte te verkleinen.

// AWS SDK v3 β€” File Upload to S3

import {
  S3Client,
  PutObjectCommand,
  GetObjectCommand,
  DeleteObjectCommand,
  ListObjectsV2Command,
} from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage'; // For multipart upload
import { fromEnv } from '@aws-sdk/credential-providers';

const s3 = new S3Client({
  region: process.env.AWS_REGION || 'us-east-1',
  credentials: fromEnv(), // Reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
});

const BUCKET = process.env.S3_BUCKET_NAME!;

// 1. Simple upload (files < 5MB)
async function uploadFile(key: string, file: Buffer, contentType: string) {
  const command = new PutObjectCommand({
    Bucket: BUCKET,
    Key: key,           // e.g., 'uploads/2026/user-123/avatar.jpg'
    Body: file,
    ContentType: contentType,
    // Optional: set cache headers
    CacheControl: 'max-age=31536000',
    // Optional: make publicly readable
    // ACL: 'public-read',
    // Optional: custom metadata
    Metadata: {
      'uploaded-by': 'server',
      'original-name': 'avatar.jpg',
    },
  });

  const result = await s3.send(command);
  return {
    url: `https://${BUCKET}.s3.amazonaws.com/${key}`,
    etag: result.ETag,
    versionId: result.VersionId,
  };
}

// 2. Multipart upload for large files (recommended for > 100MB)
async function uploadLargeFile(key: string, stream: NodeJS.ReadableStream, contentType: string) {
  const upload = new Upload({
    client: s3,
    params: {
      Bucket: BUCKET,
      Key: key,
      Body: stream,
      ContentType: contentType,
    },
    partSize: 10 * 1024 * 1024, // 10 MB parts
    queueSize: 4,                // 4 concurrent uploads
  });

  upload.on('httpUploadProgress', (progress) => {
    console.log(`Uploaded: ${progress.loaded}/${progress.total} bytes`);
  });

  return upload.done();
}

Presigned URLs voor veilige directe uploads

Presigned URLs stellen clients in staat direct naar S3 te uploaden zonder uw server.

// Presigned URLs β€” Direct Browser-to-S3 Upload

import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
import { randomUUID } from 'crypto';

// Generate presigned upload URL (browser uploads directly to S3)
async function generateUploadUrl(
  fileName: string,
  fileType: string,
  userId: string
) {
  const key = `uploads/${userId}/${randomUUID()}-${fileName}`;

  const command = new PutObjectCommand({
    Bucket: BUCKET,
    Key: key,
    ContentType: fileType,
    // Optional: limit file size with Content-Length condition
    // This must be enforced server-side with a policy
  });

  const signedUrl = await getSignedUrl(s3, command, {
    expiresIn: 15 * 60, // 15 minutes
  });

  return {
    uploadUrl: signedUrl,
    key,             // Return key so client can reference the uploaded file
    expiresIn: 900,  // seconds
  };
}

// Express.js endpoint
app.post('/api/upload-url', authenticate, async (req, res) => {
  const { fileName, fileType, fileSize } = req.body;

  // Validate file type and size on server
  const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
  if (!allowedTypes.includes(fileType)) {
    return res.status(400).json({ error: 'File type not allowed' });
  }
  if (fileSize > 10 * 1024 * 1024) {  // 10 MB limit
    return res.status(400).json({ error: 'File too large' });
  }

  const { uploadUrl, key } = await generateUploadUrl(fileName, fileType, req.user.id);
  res.json({ uploadUrl, key });
});

// Client-side: use the presigned URL to upload
async function uploadToS3(file, presignedUrl) {
  const response = await fetch(presignedUrl, {
    method: 'PUT',
    body: file,
    headers: {
      'Content-Type': file.type,
    },
  });

  if (!response.ok) throw new Error('Upload failed');
  return response;
}

CloudFront CDN-integratie

CloudFront is het CDN van AWS dat S3-inhoud wereldwijd in cache opslaat.

// CloudFront + S3 Setup

// 1. Bucket policy to allow CloudFront (Origin Access Control)
const bucketPolicy = {
  Version: '2012-10-17',
  Statement: [
    {
      Sid: 'AllowCloudFrontServicePrincipal',
      Effect: 'Allow',
      Principal: {
        Service: 'cloudfront.amazonaws.com',
      },
      Action: 's3:GetObject',
      Resource: `arn:aws:s3:::my-bucket/*`,
      Condition: {
        StringEquals: {
          'AWS:SourceArn': 'arn:aws:cloudfront::123456789:distribution/ABCDEF123456',
        },
      },
    },
  ],
};

// 2. Generate signed URLs for private CloudFront content
import { getSignedUrl } from '@aws-sdk/cloudfront-signer';

function generateCloudFrontSignedUrl(key: string, expirySeconds = 3600) {
  const url = `https://${process.env.CLOUDFRONT_DOMAIN}/${key}`;
  const expiryDate = new Date();
  expiryDate.setSeconds(expiryDate.getSeconds() + expirySeconds);

  return getSignedUrl({
    url,
    keyPairId: process.env.CLOUDFRONT_KEY_PAIR_ID!,
    privateKey: process.env.CLOUDFRONT_PRIVATE_KEY!,
    dateLessThan: expiryDate.toISOString(),
  });
}

// 3. Invalidate CloudFront cache when S3 objects change
import { CloudFrontClient, CreateInvalidationCommand } from '@aws-sdk/client-cloudfront';

const cloudfront = new CloudFrontClient({ region: 'us-east-1' });

async function invalidateCache(paths: string[]) {
  const command = new CreateInvalidationCommand({
    DistributionId: process.env.CLOUDFRONT_DISTRIBUTION_ID!,
    InvalidationBatch: {
      CallerReference: Date.now().toString(),
      Paths: {
        Quantity: paths.length,
        Items: paths.map(p => `/${p}`),
      },
    },
  });

  return cloudfront.send(command);
}

// Usage: invalidate a specific file after update
await invalidateCache(['uploads/profile-pictures/user-123.jpg']);
// Wildcard: invalidate all files in a folder
await invalidateCache(['uploads/*']);

Veelgestelde vragen

Moet ik openbare toegang tot mijn S3-bucket toestaan?

Alleen voor statische websitehosting of echt openbare assets. Houd de bucket privΓ© en gebruik presigned URLs.

Hoe lang moeten presigned URLs geldig zijn?

15-30 minuten voor upload-URLs. De maximale geldigheidsduur is 7 dagen.

Hoe verlaag ik S3-opslagkosten?

Gebruik S3 Intelligent-Tiering en levenscyclusregels.

Wat is multipart upload?

Multipart upload verdeelt grote bestanden in parallel geΓΌploade delen. Aanbevolen voor bestanden groter dan 100 MB.

Gerelateerde tools

𝕏 Twitterin LinkedIn
Was dit nuttig?

Blijf op de hoogte

Ontvang wekelijkse dev-tips en nieuwe tools.

Geen spam. Altijd opzegbaar.

Try These Related Tools

{ }JSON Formatter

Related Articles

GitHub Actions CI/CD: Complete gids

Stel CI/CD-pipelines in met GitHub Actions.

Docker Best Practices: 20 tips voor productiecontainers

Beheers Docker met 20 essentiΓ«le best practices: multi-stage builds, beveiliging, image-optimalisatie en CI/CD.

Terraform Infrastructure as Code

Leer Terraform IaC.