Загрузка файла с помощью HTML формы

Раздел содержит информацию о том, как из браузера загрузить файлы в Object Storage с помощью HTML формы.

Примечание

Через форму нельзя загрузить объекты размером более 5 ГБ (см. Квоты и лимиты).

Общее описание

Если вы хотите, чтобы пользователи вашего сервиса могли загружать файлы в ваш бакет напрямую из браузера, то:

  1. Вы разрабатываете HTML-форму, в которой есть все необходимое для отправки запроса в Object Storage и помещаете ее на страницу вашего сервиса.
  2. Пользователь открывает в браузере страницу вашего сервиса и с помощью формы загружает файл в хранилище.

Чтобы устанавливать правила и ограничения на загрузку файлов, к форме необходимо приложить политику безопасности. Политика не нужна только в том случае, если ваш бакет доступен для публичной записи без ограничений.

Для создания формы выполните следующие действия:

  1. Разработайте политику безопасности, которая описывает параметры запроса к Object Storage. Например, политика может ограничивать размер загружаемого объекта.
  2. На основании политики безопасности сгенерируйте подпись.
  3. Создайте HTML-форму с подписанной политикой безопасности, которую вы будете предлагать пользователям для загрузки файлов.

HTML-форма

Общий вид HTML страницы с формой для загрузки файла:

<html>
    <head>
        ...
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        ...
    </head>
    <body>
        ...
        <form action="https://storage.yandexcloud.net/{bucket-name}" method="post" enctype="multipart/form-data">
            ...
            <input .../>
            ...
        </form>
        ...
    </body>
</html>

HTML-форма описывается тегом <form> и состоит из объявления и полей.

Объявление формы содержит атрибуты:

  • action — URL бакета, в который необходимо загрузить объект.
  • method — HTTP метод. Значение — POST.
  • enctype — Тип содержимого запроса. Значение — multipart/form-data.

Поля формы содержат подробное описание запроса к Object Storage и ограничений, которые применяются к этому запросу.

Форма и ее поля должны быть в кодировке UTF-8. Установите атрибут charset тега <meta> страницы в значение UTF-8.

<html>
    <head>
        ...
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        ...

Поля формы

Object Storage поддерживает механизмы подписи формы AWS Signature V2 и V4. От механизма подписи зависят названия и состав полей формы. AWS Signature V2 поддержана только для совместимости, по возможности не используйте ее.

Общий вид формы:

<form action="https://storage.yandexcloud.net/{bucket-name}" method="post" enctype="multipart/form-data">
   Ключ в хранилище:
   <input type="input" name="key" value="object_key"> /><br />
   <!-- Свойства запроса -->
   <input type="hidden" name="x-amz-credential" value="access_key_id/date/ru-central1/s3/aws4_request" />
   <input type="hidden" name="acl" value="predefined-acl-name" />
   <input type="hidden" name="x-amz-algorithm" value="AWS4-HMAC-SHA256" />
   <input type="hidden" name="x-amz-date" value="date" />
   <input type="hidden" name="success_action_redirect" value="some-URL" />
   <input type="hidden" name="policy" value="base64-encoded-policy-document" />
   <input type="hidden" name="x-amz-signature" value="signature-string" />
   <!-- Прочие необходимые поля -->
   Файл для загрузки:
   <input type="file" name="file" /> <br />
   <!-- Поля после “file” игнорируются -->
   <input type="submit" name="submit" value="Загрузить" />
</form>
 <form action="https://storage.yandexcloud.net/{bucket-name}" method="post" enctype="multipart/form-data">
      Ключ в хранилище:
      <input type="input" name="key" value="object_key" />
      <!-- Свойства запроса -->
      <input type="hidden" name="AWSAccessKeyId" value="access_key_id" />
      <input type="hidden" name="acl" value="access_type" />
      <input type="hidden" name="success_action_redirect" value="url" />
      <input type="hidden" name="policy" value="base64-encoded-policy-document" />
      <input type="hidden" name="signature" value="signature_string" />
      <input type="hidden" name="Content-Type" value="content/type" />
      <!-- Прочие необходимые поля -->
      Файл для загрузки:
      <input type="file" name="file" /> <br />
      <!-- Поля после “file” игнорируются -->
      <br />
      <input type="submit" value="Загрузить файл" />
</form>

Примечание

Дальнейшее описание актуально только при использовании AWS Signature V4.

Описание полей формы:

Поле Описание Обязательное
acl ACL для объекта. Можно установить один из предопределенных ACL. Например, если вы хотите сделать объект публичным, используйте значение public-read. Нет
Cache-Control Набор директив для кеширования данных согласно RFC 2616. Нет
Content-​Disposition Имя, под которым Object Storage предложит сохранить объект как файл при выгрузке. Соответствует RFC 2616. Нет
Content-Encoding Определяет кодировку содержимого согласно RFC 2616. Нет
Content-Type MIME тип загружаемого файла. Если не указать Content-Type, то Object Storage сохраняет объект с типом application/octet-stream. В дальнейшем это может создать сложности для пользовательских программ, поскольку они не будут понимать формат файла, например браузер не сможет отобразить изображение. Нет
Expires Срок устаревания ответа. Соответствует RFC 2616. Нет
key Ключ объекта.

Можно указать ключ целиком или шаблон вида prefix/${filename}, т.е. если вы загружаете файл some_file.jpg, то итоговый ключ объекта будет prefix/some_file.jpg.
Да
policy Политика безопасности, описывающая разрешения запроса. Запросы без политики рассматриваются как анонимные и обрабатываются только для бакетов с публичным доступом на запись. Условно
x-amz-signature Подпись политики, которую необходимо сгенерировать с помощью секретного ключа.

Необходимо, если в форме есть политика безопасности.
Условно
success_action_redirect URL, на который перенаправляется пользователь после успешной загрузки файла. Если значение не установлено, то Object Storage возвращает ответ, установленный в поле success_action_status. Нет
success_action_status Статус ответа при успешной загрузке.

Если не указан success_action_redirect, то Object Storage возвращает значение success_action_status. Тело ответа пустое.

Допустимые значения: 200, 204 (по умолчанию).
Нет
x-amz-algorithm Алгоритм для подписи политики безопасности. Значение — AWS4-HMAC-SHA256.

Необходимо, если в форме есть политика безопасности.
Условно
x-amz-credential Идентификатор для подписи.

Строка формата <access-key-id>/<date>/ru-central1/s3/aws4_request, где <date> должна совпадать со значением поля x-amz-date и той датой, которая используется для подписи политики.

Необходимо, если в форме есть политика безопасности.
Условно
x-amz-date Дата в формате ISO8601, например, 20180719T000000Z. Должна по значению (не по формату) совпадать с датой в поле x-amz-credential, а также с датой, которая используется для подписи политики.

Необходимо, если в форме есть политика безопасности.
Условно
x-amz-storage-class Класс хранилища для объекта. С помощью HTML-формы вы можете поместить объект только в Стандартное хранилище. Нет
x-amz-meta-* Пользовательские метаданные объекта.

Все заголовки, начинающиеся с x-amz-meta- Object Storage воспринимает как пользовательские, не обрабатывает их и сохраняет в том виде, в котором они переданы.

Общий размер пользовательских заголовков не должен превышать 2KB. Размер пользовательских данных определяется как длина строки в кодировке UTF-8. В размере учитываются и названия заголовков и их значения.
Нет
x-amz-website- redirect-location Если бакет сконфигурирован как веб-сайт, то это поле устанавливает редирект с заданного объекта на какой-либо другой в этом бакете или на произвольный URL в интернете. Редирект сохраняется в метаданных объекта. Нет
file Поле ввода, позволяющее пользователю выбрать файл для загрузки. Поле должно быть последним в форме. Все поля, указанные после file, игнорируются. Нельзя загрузить более одного файла в одном запросе. Да

Политика безопасности

HTML-форма содержит политику безопасности, которая накладывает ограничения на файлы, которые можно загрузить.

Политика безопасности представляет собой документ JSON и может выглядеть, например, следующим образом:

{
    "expiration": "timestamp",
    "conditions": [
        {"bucket": "bucket-name"},
        ["starts-with", "$key", "users-uploads/"],
        {"acl": "public-read"},
        {"success_action_redirect": "http://localhost/"},
        ["starts-with", "$Content-Type", ""],
        ["content-length-range", 0, 1048576]
    ]
}

Поле expiration содержит срок действия политики в формате ISO8601, например, 20190722T153936Z. По истечению срока действия политики Object Storage перестает принимать файлы, загружаемые с помощью формы.

Поле conditions содержит набор правил для полей формы. Хотя бы одно правило должно быть указано для каждого поля формы.

Правила политики безопасности могут быть следующих типов:

Тип правила Описание
Точное совпадение Поле в форме должно иметь в точности то значение, которое указано в политике.

Например, {"acl": "public-read"}. Также возможна альтернативная форма записи: [ "eq", "$acl", "public-read" ].
Частичное совпадение Значение поля в форме должно начинаться с указанной в политике строки.

Например, ["starts-with", "$key", "key_prefix"]. Если в качестве значения указана пустая строка, то соответствующее поле может принимать любое значение.

Например, ["starts-with", "$Content-Type", ""].
content-length-range Ограничение размера загружаемого объекта.

Например, ["content-length-range", 0, 1048576].

Возможные ограничения:

Элемент Тип ограничения Область ограничения
acl Полное и частичное совпадение. Поле формы acl.
bucket Полное и частичное совпадение. Имя бакета.
content-length-range content-length-range content-length-range
key Полное и частичное совпадение. Поле формы key. Позволяет задать ключ объекта или префикс.
success_action_redirect Полное и частичное совпадение. Поле формы success_action_redirect.
success_action_status Полное и частичное совпадение. Поле формы success_action_status.
x-amz-* Полное совпадение. Поля формы x-amz-*, кроме x-amz-meta-*.
x-amz-meta-* Полное и частичное совпадение. Поля формы x-amz-meta-*.
Cache-Control
Content-Disposition
Content-Encoding
Content-Type
Expires
Полное и частичное совпадение. Одноименные поля формы.

Если поле key имеет форму шаблона, то политика применяется после подстановки в шаблон заданного пользователем имени файла.

Подпись политики безопасности

Общий алгоритм подписи политики:

  1. Закодировать JSON-документ политики в base64.
  2. Сгенерировать подписывающий ключ.
  3. Сгенерировать подпись политики.

Пример генерирования формы с помощью boto3

Входные условия:

  • Файлы должны сохраняться в бакет user-data с префиксом /users/upload/.
  • Загруженные объекты открыты для публичного чтения.
  • В случае успешной загрузки происходит перенаправление на страницу https://cloud.yandex.ru/docs/storage/concepts/presigned-post-forms.

Для генерирования полей формы воспользуемся boto3 Python SDK:

aws_access_key_id = 'JK38EXAMPLEAKDID8'
aws_secret_access_key = 'ExamP1eSecReTKeykdokKK38800'
endpoint = 'https://storage.yandexcloud.net'

s3 = boto3.client('s3',
                  aws_access_key_id=aws_access_key_id,
                  aws_secret_access_key=aws_secret_access_key,
                  region_name='ru-central1',
                  endpoint_url=endpoint,
                  config=botocore.client.Config(signature_version='s3v4'),
                  )

key = 'users/uploads/${filename}'
bucket = 'user-data'
conditions = [{"acl":"public-read"}, ["starts-with", "$key", "users/uploads"], {'success_action_redirect': 'https://cloud.yandex.ru/docs/storage/concepts/presigned-post-forms'}]
fields = {'success_action_redirect': 'https://cloud.yandex.ru/docs/storage/concepts/presigned-post-forms'}

prepared_form_fields = s3.generate_presigned_post(Bucket=bucket,
                                                  Key=key,
                                                  Conditions=conditions,
                                                  Fields=fields,
                                                  ExpiresIn=60 * 60)


print(prepared_form_fields)

Скрипт вернет документ JSON следующего вида:

{
    'url': u'https://storage.yandexcloud.net/user-data',
    'fields': {
        'x-amz-algorithm': 'AWS4-HMAC-SHA256',
        'x-amz-date': '20190722T153936Z',
        'success_action_redirect': 'https://cloud.yandex.ru/docs/storage/concepts/presigned-post-forms',
        'x-amz-signature': '4bdfb2209fc30744458be10bc3b99361f2f50add20f2ca2425587a2722859f96',
        'key': 'users/uploads/${filename}',
        'policy': u'eyJjb25kaXRpb25zIj...M5OjM2WiJ9',
        'x-amz-credential': u'JK38EXAMPLEAKDID8/20190722/ru-central1/s3/aws4_request'}
}

Используя значения из выданного документа, можно построить HTML-страницу с формой для отправки файла:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    </head>
    <body>
        <form action="https://storage.yandexcloud.net/user-data" method="post" enctype="multipart/form-data">
            Ключ в хранилище:
            <input type="input"    name="key" value="users/uploads/${filename}" /><br />
            <input type="hidden"   name="x-amz-credential" value="JK38EXAMPLEAKDID8/20190722/ru-central1/s3/aws4_request" />
            <input type="hidden"   name="acl" value="public-read" />
            <input type="hidden"   name="x-amz-algorithm" value="AWS4-HMAC-SHA256" />
            <input type="hidden"   name="x-amz-date" value="20190722T153936Z" />
            <input type="hidden"   name="success_action_redirect" value="https://cloud.yandex.ru/docs/storage/concepts/presigned-post-forms" />
            <input type="hidden"   name="policy" value="eyJjb25kaXRpb25zIj...M5OjM2WiJ9" />
            <input type="hidden" name="x-amz-signature" value="4bdfb2209fc30744458be10bc3b99361f2f50add20f2ca2425587a2722859f96" />
            Файл для загрузки:
            <input type="file"   name="file" /> <br />
            <input type="submit" name="submit" value="Загрузить" />
        </form>
    </body>
</html>