Как прочитать тело HTTP-запроса, если в нем передаются текстовые поля и файл (картинка)?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке HTTP-сервисов в среде 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда стороннее приложение или веб-сайт присылает запрос, содержащий одновременно и текстовую информацию (например, статус или комментарий), и бинарные данные (например, изображение в формате JPEG). В этой статье мы подробно разберем, как правильно обрабатывать такие запросы, почему стандартный метод чтения строки может не подойти и какие современные инструменты платформы следует использовать для эффективного решения задачи.

Постановка задачи и анализ входящих данных

Представим ситуацию: на ваш HTTP-сервис приходит POST-запрос. В теле запроса передаются три элемента: поле status, поле comment и файл image.jpg. Если мы попытаемся прочитать тело запроса простым методом Запрос.ПолучитьТелоКакСтроку(), мы увидим текстовую "кашу", в которой перемешаны служебные заголовки, границы разделов (boundary) и нечитаемые символы бинарного файла.

Для начала проанализируем, какие методы предоставляет объект HTTPСервисЗапрос:

  1. ПолучитьТелоКакСтроку() — идеально подходит для JSON или XML, но "ломает" бинарные данные при попытке интерпретировать их как текст.
  2. ПолучитьТелоКакДвоичныеДанные() — возвращает всё тело целиком в виде объекта ДвоичныеДанные. Это безопасный способ, сохраняющий целостность картинки, но требующий последующего ручного разбора.

Разберем, почему данные приходят в таком виде. Когда клиент отправляет форму с файлом, используется заголовок Content-Type: multipart/form-data; boundary=----WebKitFormBoundary.... Это означает, что тело запроса разделено на части специальной строкой-разделителем.

Шаг 1: Анализ заголовков запроса

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


// В методе HTTP-сервиса (например, POST)
ТипСодержимого = Запрос.Заголовки.Получить("Content-Type");
Если СтрНайти(ТипСодержимого, "multipart/form-data") > 0 Тогда
    // Мы имеем дело со смешанными данными
    // Нужно найти разделитель (boundary)
    ПозицияГраницы = СтрНайти(ТипСодержимого, "boundary=");
    Разделитель = Сред(ТипСодержимого, ПозицияГраницы + СтрДлина("boundary="));
КонецЕсли;

Знание boundary критически важно, так как именно эта строка отделяет ваш статус от комментария, а комментарий от тела картинки.

Шаг 2: Использование современных инструментов (ЧтениеДанных)

Начиная с версии платформы 8.3.10, в 1С появились мощные инструменты для работы с потоками. Проанализируем ситуацию: если файл картинки весит несколько мегабайт, считывание его целиком в память как ДвоичныеДанные может быть неэффективным. Вместо этого мы воспользуемся объектом ЧтениеДанных.

Рассмотрим алгоритм работы с потоком тела запроса:


// Получаем поток из тела запроса
ПотокТела = Запрос.ПолучитьТелоКакПоток();
Чтение = Новый ЧтениеДанных(ПотокТела);

// В реальной задаче здесь должен быть цикл по частям multipart
// Для упрощения разберем логику получения конкретной части
Пока Истина Цикл
    // Читаем данные до разделителя
    // Это сложный процесс парсинга MIME-заголовков каждой части
    Прервать; // Условный выход
КонецЦикла;

Шаг 3: Разбор составного тела (Multipart Parsing)

Поскольку встроенного автоматического парсера multipart/form-data для HTTP-сервисов в 1С "из коробки" (в одну команду) не существует, нам придется выполнить следующие действия:

  1. Прочитать поток тела запроса.
  2. Найти в потоке позиции строк-разделителей.
  3. Между разделителями извлечь заголовки части (например, Content-Disposition: form-data; name="status").
  4. Выделить само значение поля или содержимое файла.

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

Шаг 4: Практический пример обработки полей и картинки

Рассмотрим более детальный пример, когда мы точно знаем структуру запроса. Допустим, мы решили прочитать всё тело как ДвоичныеДанные и затем извлечь из него картинку.


ТелоДанные = Запрос.ПолучитьТелоКакДвоичныеДанные();

// В данном случае мы можем воспользоваться объектом РазделениеДвоичныхДанных
// или сохранить во временный файл и работать с ним через ЧтениеДанных
ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
ТелоДанные.Записать(ИмяВременногоФайла);

ФайлПоток = Новый ФайловыйПоток(ИмяВременногоФайла, РежимОткрытияФайла.Открыть);
Чтение = Новый ЧтениеДанных(ФайлПоток);

// Читаем данные порциями, ищем boundary
// При нахождении заголовка картинки "image/jpeg"
// Сохраняем последующие данные в новый файл до следующего boundary

Важный момент: Если данные передаются в формате JSON, но внутри JSON одно из полей содержит картинку, она будет передана в кодировке Base64. В этом случае алгоритм гораздо проще:


// Если Content-Type: application/json
СтрокаJSON = Запрос.ПолучитьТелоКакСтроку();
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
СтруктураДанных = ПрочитатьJSON(ЧтениеJSON);

Статус = СтруктураДанных.status;
Комментарий = СтруктураДанных.comment;
ДвоичныеДанныеКартинки = Base64Значение(СтруктураДанных.image_base64);

Рекомендации по работе с изображениями

Проанализируем ситуацию, когда картинка успешно получена. Что с ней делать дальше? В 1С есть несколько вариантов хранения:

Для загрузки полученных ДвоичныхДанных в справочник, используем стандартный метод:


НовыйОбъект = Справочники.НоменклатураПрисоединенныеФайлы.СоздатьЭлемент();
НовыйОбъект.ФайлХранилище = Новый ХранилищеЗначения(ДвоичныеДанныеКартинки);
НовыйОбъект.Наименование = "ЗагруженноеИзображение.jpg";
НовыйОбъект.Записать();

Заключение

Мы рассмотрели основные способы получения данных из тела HTTP-запроса. Подведем итоги:

  1. Всегда проверяйте Content-Type в заголовках запроса.
  2. Если передается файл — используйте ПолучитьТелоКакДвоичныеДанные() или ПолучитьТелоКакПоток().
  3. Для разбора multipart/form-data используйте новые инструменты платформы: ЧтениеДанных, ПотокДанных и БуферДвоичныхДанных.
  4. Никогда не пытайтесь преобразовать всё тело с картинкой в одну строку через ПолучитьТелоКакСтроку(), так как это приведет к порче бинарных данных.

Используя эти подходы, вы сможете корректно принимать данные от любых внешних систем, будь то мобильные приложения, веб-формы или сторонние API.

← На главную