Учебник веб-разработки
Разделы учебника
На этой странице

IX. Strapi и медиа

Объектное хранение и S3: что, зачем и по какому адресу

Оглавление · Модели хранения · Garage

Задача: проследить путь байтов фотографии и отличить адрес объекта от его публичного URL. Нужны HTTP и различие файла и записи о файле.

Где хранить байты

ВариантЧто удобноЧто нужно продумать
Файловая система хостаПрямой доступ через файловый APIПрава, пути, резервная копия и доступ других процессов
Docker volumeСохранение данных вне слоя контейнераПривязка к хосту, копирование и восстановление
База данныхБайты вместе с транзакционными даннымиОбъём, доставка файлов и нагрузка на БД
Объектное хранилищеДоступ к байтам через API по ключуДоступ, метаданные, целостность связей и восстановление

Отдельное хранилище полезно, когда файлы должны обслуживаться независимо от процесса приложения. Для небольшого локального инструмента может хватать каталога. Volume — способ сохранить данные контейнера, а не другой вид облачного API. Garage сам использует тома, чтобы сохранять объекты и служебные данные.

S3 — сервис и семейство совместимых API

Amazon S3 — объектное хранилище AWS. Bucket содержит объекты; объект имеет key, содержимое и метаданные. Ключ идентифицирует объект внутри bucket. Модель Amazon S3. Вводная модель здесь относится к обычному объектному bucket, не ко всем специальным типам bucket, появляющимся в AWS.

«S3-compatible» означает поддержку определённой части API. Это не обещание всех возможностей AWS, одинаковых прав, пределов или согласованности. Atmanki использует Garage 2.3.0; настройки и ограничения сверяем отдельно. Совместимость Garage.

Математическая модель без версионирования: (bucket, key) → (bytes, metadata). Если версионирование включено и поддерживается, идентичность чтения может включать version ID. Это не строка таблицы CMS и не путь на диске операционной системы.

Bucket, key, prefix, endpoint и region

ПонятиеУчебный примерРоль
BucketmediaКонтейнер объектов
Keystrapi/a.jpgИмя конкретного объекта внутри bucket
Prefixstrapi/Начало ключа, по которому можно группировать/искать
API endpointhttp://s3:3900Адрес S3-протокола в Docker-сети
RegiongarageПараметр настройки клиента для этого хранилища
Public originhttp://media.localhost:8080Адрес чтения для браузера

В обычной плоской модели / — часть key; префикс не создаёт каталог с POSIX-правами. Папки интерфейса могут быть представлением ключей. Ключи Amazon S3. Папки медиабиблиотеки Strapi — ещё один уровень организации: они не обязаны переносить объект или менять key.

Path-style обращение помещает bucket в путь: endpoint/media/strapi/a.jpg. Virtual-hosted style использует имя bucket в host. Адресация AWS. В конфигурации проекта forcePathStyle=true; публичный website URL строится другим путём. Не собирайте подпись S3 вручную по этой иллюстрации: SDK учитывает запрос и настройки.

Основные операции

ОперацияЧто выясняем
PutObjectСохранить объект по ключу
GetObjectПолучить байты
HeadObjectПолучить сведения без тела объекта
ListObjectsV2Перечислить объекты с учётом префикса и пагинации
DeleteObjectУдалить по правилам выбранного bucket

Список метаданных не является скачиванием всех байтов. Одной страницы listing может быть недостаточно для аудита. ListObjectsV2. Удаление при версионировании может иметь иной смысл, чем физическое исчезновение всех версий. Удаление версий AWS. Для каждого продукта проверяйте поддерживаемый контракт, а не переносите ожидания из локальной папки.

У объекта есть Content-Type и другие метаданные. Заявленный MIME не доказывает, что внутри допустимое изображение. ETag — не универсальный MD5 файла: его смысл зависит от способа записи и настроек. Сведения об объекте AWS. Для проверки целостности заранее определите checksum и сравниваемые байты.

Multipart upload разбивает один объект на части: начало, загрузка частей, завершение; при отказе нужен разбор или отмена незавершённой загрузки. Это не HTML multipart/form-data, где форма передаёт поля и файлы HTTP-обработчику. Multipart S3. Порог и поведение SDK зависят от конфигурации; они не следуют из размера файла в нашем учебном примере.

Доступ и подписанные URL

Credentials разрешают операции клиента с хранилищем. Долговременный secret не передаётся браузеру. Публичное чтение — отдельная политика, а не отсутствие server-side credentials для загрузки.

Presigned URL разрешает определённый запрос от имени подписавшего клиента в пределах его прав и срока действия. URL можно использовать повторно, пока он действителен; это не одноразовый билет. Ограничения credentials также влияют на срок. Для upload уже существующий key может быть перезаписан по контракту. Подписанные URL AWS.

Исходник схемы
sequenceDiagram
  participant Browser as Браузер
  participant App as Приложение
  participant Store as Объектное хранилище
  Browser->>App: Запрос разрешения на загрузку
  App->>App: Проверить пользователя и параметры
  App-->>Browser: URL ограниченного запроса
  Browser->>Store: Загрузка по подписанному URL
  Store-->>Browser: Результат
  Browser->>App: Завершение загрузки для проверки и связи

Это будущий вариант интеграции, не действующий endpoint Atmanki. Приложение должно проверить завершение, key, формат и владение перед связыванием файла. Совместимость presigned-запросов с конкретной версией Garage проверяют отдельно. Не печатайте приватный подписанный URL в публичной документации.

Два пути в Atmanki

Исходник схемы
flowchart LR
  Editor["Редактор"] --> CMS["Strapi upload"]
  CMS -->|"S3 API: 3900"| API["Garage: bucket media"]
  CMS --> DB["CMS: запись файла и связи"]
  Browser["Браузер: /a.jpg"] --> Proxy["Caddy"]
  Proxy -->|"/strapi/a.jpg, website: 3902"| Website["Garage website endpoint"]
  Website --> API

Схема разделяет операции, не изображает единую транзакцию. Provider задаёт rootPath=strapi, S3_ENDPOINT, S3_PUBLIC_URL, forcePathStyle и ACL:undefined. Последнее важно для Garage, который не поддерживает AWS ACL; это не команда открыть доступ всем. Website-доступ bucket разрешён отдельно, как описано в инструкции.

CMS-адаптер проверяет origin и форму пути, выдаёт чистый public URL. Caddy добавляет strapi/ и выставляет Host для website endpoint. Старые /strapi/... остаются доступны; старые local uploads идут через /api/media/... . Внутренний API endpoint не становится адресом изображения для браузера.

CORS задаёт возможность браузерному скрипту читать cross-origin ответы; он не заменяет права хранилища. Обычное отображение изображения и доступ JS к его данным — разные сценарии. CORS S3. Кеширование публичного HTTP-ответа разобрано в главе о кешах.

Практика

Для вымышленного a.jpg выпишите отдельно bucket, key, API endpoint, website host и public URL. Найдите конфигурации, которые связывают их. Объясните, почему папка в Strapi, key и путь браузера могут различаться.

Продолжите в главе о жизненном цикле медиа: успешная загрузка, запись CMS, публикация и восстановление требуют разных свидетельств.