Вступ
У сучасних веб-додатках важливо ефективно та безпечно обробляти завантаження файлів. AWS S3 (Simple Storage Service) пропонує надійне рішення для зберігання файлів, а використання попередньо підписаних URL додає додатковий рівень безпеки, спрощуючи процес завантаження. У цьому детальному посібнику ми створимо повну систему керування файлами з відслідковуванням прогресу завантаження, функціональністю завантаження та чистим інтерфейсом користувача.
Розуміння попередньо підписаних URL
Попередньо підписані URL — це тимчасові URL-адреси, які надають специфічні дозволи для виконання операцій з об'єктами S3. Замість того, щоб давати клієнтам прямий доступ до вашого бакету S3, ви генеруєте тимчасові URL-адреси, які з часом стають недійсними.
Переваги:
- Дозволяють користувачам завантажувати файли без надання їм облікових даних AWS
- Надають тимчасовий, безпечний доступ для виконання конкретних операцій
- Створюють можливості для завантаження файлів на клієнтській стороні веб-додатків
Передумови:
- Встановлений Node.js
- Обліковий запис AWS
- Базові знання React та Express
Налаштування AWS
1. Створіть бакет S3
- Перейдіть до S3 в AWS Console
- Натисніть
Create bucket
- Налаштуйте бакет:
- Введіть унікальне ім’я бакету
- Виберіть регіон (не забудьте це для вашого додатку)
- Зніміть позначку з "Block all public access" (необхідно для попередньо підписаних URL)
- Увімкніть версіонування (рекомендується)
- Натисніть “Create bucket”
2. Налаштування CORS для бакету
- Виберіть ваш бакет
- Перейдіть на вкладку “Permissions”
- Прокрутіть до “Cross-origin resource sharing (CORS)”
- Натисніть “Edit” і додайте таку конфігурацію:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["PUT", "GET", "POST", "DELETE", "HEAD"],
"AllowedOrigins": ["*"],
"ExposeHeaders": ["ETag"]
}
]
3. Створіть користувача IAM для доступу
- Перейдіть до IAM в AWS Console
- Натисніть
Users
→Add user
- Налаштування користувача:
- Ім’я користувача:
s3-presigned-user-medium
- Виберіть
Access key — Programmatic access
- Встановіть дозволи
- Знайдіть і виберіть
AmazonS3FullAccess
(Для продакшн-середовища створіть користувацьку політику з обмеженим доступом) - Перегляньте та створіть користувача
- ВАЖЛИВО: Завантажте або скопіюйте Access Key ID та Secret Access Key
4. Налаштування середовища
Створіть файл .env
у вашому проекті:
AWS_ACCESS_KEY_ID=your_access_key_id
AWS_SECRET_ACCESS_KEY=your_secret_access_key
AWS_REGION=your_region
AWS_BUCKET_NAME=your_bucket_name
Початкове налаштування:
// Створіть директорії проекту
mkdir s3-file-uploader
cd s3-file-uploader
// Створіть директорію для бекенду
mkdir server
cd server
npm init -y
// Встановіть залежності для бекенду
npm install express @aws-sdk/client-s3 @aws-sdk/s3-request-presigner dotenv cors
// Створіть фронтенд
cd ..
npx create-react-app client
cd client
npm install axios
Реалізація бекенду
Створіть файл app.js
у директорії серверу:
import express from 'express';
import { S3Client, PutObjectCommand, GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import dotenv from 'dotenv';
import cors from 'cors';
dotenv.config();
const app = express();
app.use(cors());
app.use(express.json());
const s3Client = new S3Client({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
});
Ендпоінт для генерації URL для завантаження
app.post('/api/generate-upload-url', async (req, res) => {
try {
const { fileName, fileType } = req.body;
const command = new PutObjectCommand({
Bucket: process.env.AWS_BUCKET_NAME,
Key: `uploads/${fileName}`,
ContentType: fileType,
});
const uploadURL = await getSignedUrl(s3Client, command, { expiresIn: 3600 });
res.json({ uploadURL });
} catch (error) {
console.error('Помилка при генерації URL для завантаження:', error);
res.status(500).json({ error: 'Не вдалося створити URL для завантаження' });
}
});
Цей ендпоінт:
- Приймає
fileName
іfileType
у тілі запиту - Створює попередньо підписаний URL, який дійсний протягом 1 години (3600 секунд)
- Повертає URL, який фронтенд може використати для прямого завантаження на S3
Ендпоінт для переліку файлів
app.get('/api/files', async (req, res) => {
try {
const command = new ListObjectsV2Command({
Bucket: process.env.AWS_BUCKET_NAME,
Prefix: 'uploads/'
});
const { Contents } = await s3Client.send(command);
const files = Contents
.filter(item => item.Size > 0)
.map(item => ({
name: item.Key.replace('uploads/', ''),
size: item.Size,
lastModified: item.LastModified
}));
res.json(files);
} catch (error) {
console.error('Помилка при переліку файлів:', error);
res.status(500).json({ error: 'Не вдалося отримати список файлів' });
}
});
Цей ендпоінт:
- Переліковує всі файли в бакеті S3, що мають префікс ‘uploads/’
- Фільтрує порожні файли/папки
- Повертає спрощену інформацію про файли, включаючи ім’я, розмір та дату останнього редагування
Генерація URL для завантаження:
app.get('/api/generate-download-url/:fileName', async (req, res) => {
try {
const { fileName } = req.params;
const command = new GetObjectCommand({
Bucket: process.env.AWS_BUCKET_NAME,
Key: `uploads/${fileName}`,
ResponseContentDisposition: `attachment; filename="${fileName}"`,
});
const downloadURL = await getSignedUrl(s3Client, command, { expiresIn: 3600 });
res.json({ downloadURL });
} catch (error) {
console.error('Помилка при генерації URL для завантаження:', error);
res.status(500).json({ error: 'Не вдалося створити URL для завантаження' });
}
});
Цей ендпоінт:
- Приймає
fileName
як параметр URL - Створює попередньо підписаний URL для завантаження конкретного файлу
- Встановлює параметр
content-disposition
, щоб завантаження відбулося у браузері - Повертає URL, який дійсний протягом 1 години
Розробка фронтенду
(Ось доступний вихідний код. Ви можете перевірити код фронтенду тут.)
Для завантаження:
- Фронтенд надсилає інформацію про файл для генерації URL для завантаження
- Бекенд генерує попередньо підписаний URL
- Фронтенд використовує цей URL для прямого завантаження на S3
- Прогрес завантаження відстежується на фронтенді
Для переліку файлів:
- Фронтенд викликає ендпоінт для файлів
- Бекенд переліковує об'єкти з S3
- Фронтенд відображає список файлів
Для завантаження:
- Фронтенд запитує URL для завантаження конкретного файлу
- Бекенд генерує попередньо підписаний URL
- Фронтенд ініціює завантаження, використовуючи цей URL
Ця реалізація забезпечує безпечний та ефективний спосіб обробки завантаження та завантаження файлів з використанням AWS S3.
Використання попередньо підписаних URL забезпечує безпеку при збереженні хороших показників продуктивності та досвіду користувача.
Дякую за увагу!
Перекладено з: Building a Secure File Upload System with AWS S3 Pre-signed URLs, React, and Node.js