Как добавить загрузку файлов в приложение: хранилище, лимиты и безопасность
Чтобы добавить загрузку файлов в приложение, храните файлы в объектном хранилище (bucket), а не на диске сервера и не в базе данных, а в базе сохраняйте небольшую запись с ключом файла, именем, размером, типом и владельцем. Проверяйте размер и тип файла на сервере, заранее решите, будут ли файлы публичными (как фотографии товаров) или приватными (как счета), и отдавайте приватные файлы только после проверки того, кто запрашивает. В ИИ-конструкторе функцию загрузки можно описать одним промптом; важнее всего проверить, что файлы переживают повторное развёртывание и не открываются не тем людям.
Решите, какие загрузки вам нужны
До сборки ответьте на три вопроса:
- Какие файлы? Фото профиля, фото товаров, PDF, таблицы, аудио, видео. От этого зависят ограничения типа и размера.
- Кто может их видеть? Все (публичная галерея) или только загрузивший и администраторы (договоры, документы, удостоверения, файлы клиентов).
- Что происходит после загрузки? Просто сохранить, показать превью, уменьшить изображения или прочитать содержимое.
Публичные изображения и приватные документы требуют разных настроек, поэтому сначала определитесь с этим.
Где должны храниться файлы
| Вариант | Как работает | Для чего подходит | На что обратить внимание |
|---|---|---|---|
| Объектное хранилище (bucket) | Файлы лежат в сервисе, созданном для них; база хранит ключ или ссылку | Почти любое приложение | Правила доступа нужно настроить правильно |
| Хранилище от платформы | Ваш ИИ-конструктор или хостинг включает для вас bucket | Приложения, собранные на этой платформе | Лимиты и цены определяет платформа |
| Диск сервера | Файлы пишутся в файловую систему сервера приложения | Только локальная разработка | Часто очищается при перезапуске или повторном развёртывании |
| В базе данных | Байты файла хранятся в таблице | Почти никогда | Раздувает базу, замедляет бэкапы |
| Сторонний виджет загрузки | Размещённый сервис загрузки ведёт весь процесс | Тяжёлые медиа, трансформация изображений | Ещё один поставщик, аккаунт и счёт |
Для большинства приложений правильный ответ — объектное хранилище плюс запись в базе данных. Запись в базе — то, что запрашивает ваше приложение («покажи документы этого пользователя»); bucket лишь хранит байты.
Публичные и приватные файлы
- Публичные файлы (фото товаров, изображения блога, аватары) можно отдавать по публичному адресу. Открыть их может любой, у кого есть ссылка, и для такого контента это нормально.
- Приватные файлы (счета, договоры, медицинские или удостоверяющие документы, файлы клиентов) никогда не должны иметь угадываемый публичный адрес. Сервер проверяет, что вошедший пользователь владеет файлом или имеет на него право, а затем либо отдаёт файл потоком, либо возвращает подписанный URL — ссылку, которая работает только ограниченное время.
Распространённая и серьёзная ошибка — приватные файлы в публичном bucket с предсказуемыми именами. Тот, кто угадает /uploads/invoice-102.pdf, получит чужой счёт.
Примеры промптов
Загрузка публичных изображений:
Позволь администраторам загружать до 5 фото на каждый товар. Принимай JPG, PNG и WebP до 5 МБ каждый. Сохраняй файлы в файловом хранилище, записывай ключ, размер и порядок каждого файла в таблицу product_images и показывай миниатюры с кнопкой удаления. Проверяй тип и размер на сервере, а не только в браузере.
Загрузка приватных документов:
Добавь страницу «Документы» для вошедших клиентов. Клиенты могут загружать PDF до 20 МБ. Файлы приватные: храни их в файловом хранилище, записывай ID владельца, исходное имя файла, размер и время загрузки в таблицу documents, а скачивать их могут только владелец и администраторы. Скачивание идёт через серверный маршрут, который проверяет права. Никогда не показывай публичный URL для этих файлов.
Полезные уточнения:
Показывай индикатор прогресса во время загрузки и понятную ошибку, если файл слишком большой или неподходящего типа.
Когда запись о документе удаляется, удаляй и сохранённый файл.
Пошагово
- Определите типы и ограничения размера для каждого поля загрузки. Будьте конкретны: «PDF до 20 МБ», а не «документы».
- Включите хранилище. В ИИ-конструкторе попросите загрузку в чате — он настроит хранилище; в других местах создайте bucket и добавьте его учётные данные как секреты сервера.
- Создайте таблицу в базе для записей о файлах: ID, владелец, ключ в хранилище, исходное имя, тип, размер, время создания.
- Постройте маршрут загрузки на сервере: проверьте, что пользователь вошёл, проверьте тип и размер, сгенерируйте безопасный ключ хранения (не имя файла пользователя), сохраните файл, вставьте запись.
- Постройте путь скачивания или показа: публичный URL для публичных файлов; маршрут с проверкой прав или подписанный URL для приватных.
- Постройте интерфейс: выбор файла, при необходимости перетаскивание, прогресс, превью, ошибки.
- Продумайте удаление, чтобы удаление записи удаляло и сам файл.
- Проверьте: загрузите, перезагрузите страницу, опубликуйте или повторно разверните, и убедитесь, что файл по-прежнему открывается. Затем войдите другим пользователем и попробуйте открыть приватный файл первого.
Частые ошибки
- Писать загрузки на диск сервера. В разработке это работает, а после перезапуска или повторного развёртывания файлы исчезают.
- Доверять проверкам в браузере. Атрибут «accept» у поля выбора файла — подсказка, а не безопасность. Проверяйте тип и размер на сервере.
- Использовать имя файла пользователя как ключ хранения. Имена совпадают и могут содержать странные символы. Генерируйте уникальный ключ, а исходное имя храните отдельно.
- Публичные bucket для приватных файлов. См. выше; именно эта ошибка попадает в новости.
- Разрешать любой тип файла. HTML или SVG, отданные с вашего домена, в некоторых конфигурациях могут выполнять скрипты. Принимайте только нужные типы.
- Нет ограничения размера. Один огромный файл может съесть ваш лимит хранилища или привести к таймауту запроса.
- Осиротевшие файлы. Удаление записи в базе без удаления файла постепенно заполняет хранилище, за которое вы платите.
- Забыть про мобильные устройства. Фото с телефона могут быть большими и в таких форматах, как HEIC; решите, принимать ли их или конвертировать.
Чек-лист
- Файлы хранятся в объектном хранилище, а не на диске сервера и не в базе данных
- У каждого файла есть запись в базе с владельцем, ключом, именем, типом и размером
- Тип и размер проверяются на сервере
- Ключи хранения генерируются, а не берутся из имени файла
- Приватные файлы отдаются только после проверки прав
- Другой пользователь не может открыть ваши приватные файлы, даже зная ссылку
- Удаление записи удаляет файл
- Файлы открываются после публикации или повторного развёртывания
- Ошибки загрузки показываются понятно, в том числе на телефоне
Загрузка файлов в Mythex
Mythex может автоматически включить файловое хранилище для проекта, когда приложению нужна загрузка, так что bucket вручную создавать не придётся. Также можно ввести /storage в чате. Оно доступно на Free и Pro, при этом на Free есть лимит 1 ГБ, а статус можно посмотреть в разделе Настройки → Хранилище.
В документации прямо сказано, что опубликованный хостинг — не постоянная локальная файловая система, поэтому попросите агента использовать хранилище платформы, а не сохранять на диск. Хранение файлов и скачивания списываются с баланса кредитов по объёму и по тому, сколько скачивается; на Pro тариф вдвое дешевле, чем на Free. См. Файловое хранилище в документации.
Загрузки обычно идут вместе с базой данных для записей о файлах и входом для приватных файлов. Если вы создаёте место, где клиенты обмениваются документами, см. как создать клиентский портал, а перед запуском пройдите чек-лист безопасности.
Вопросы
Где должны храниться загруженные файлы?
В объектном хранилище (сервисе, созданном для файлов, его часто называют bucket), а не на диске сервера приложения и не внутри базы данных. В своей базе храните только ключ или ссылку на файл, а также такие данные, как имя, размер и владелец.
Почему загруженные файлы пропадают после публикации или повторного развёртывания?
Большинство хостингов не сохраняют постоянный локальный диск: когда приложение перезапускается или развёртывается заново, файлы, записанные на его диск, теряются. Сохраняйте загрузки в объектном хранилище.
Как сделать загруженные файлы приватными?
Не делайте файлы публично доступными для чтения. Пусть сервер проверяет, что вошедший пользователь имеет право видеть файл, и затем отдаёт его или возвращает короткоживущую подписанную ссылку на него.
Поддерживает ли Mythex загрузку файлов?
Да. Mythex может включить для проекта файловое хранилище, когда приложению нужна загрузка, на тарифах Free и Pro, с лимитом 1 ГБ на Free. Попросите агента о функции загрузки или введите /storage.