Работа с HTTP-запросами — базовая задача при интеграции 1С с внешними системами (REST API, веб-сервисы, обмен данными). Под «получением тела запроса» обычно понимают две разные задачи в зависимости от роли 1С:
- Клиентская сторона (1С как потребитель API): как сформировать и отправить тело запроса (POST, PUT, PATCH).
- Серверная сторона (1С как веб-сервис/HTTP-сервис): как прочитать и разобрать тело входящего запроса.
Ниже подробно разобраны оба сценария с примерами кода для платформы 1С:Предприятие 8.3 (актуально для 8.2 с учетом отличий в клиентском/серверном контексте).
1С выступает в роли HTTP-клиента (Отправка тела запроса)
Здесь «получение» подразумевает подготовку объекта HTTPЗапрос и заполнение его тела данными перед отправкой через HTTPСоединение.
Основные методы класса HTTPЗапрос для работы с телом
- УстановитьТелоИзСтроки(<Строка>, <Кодировка>, <Content-Type>) — универсальный способ передать JSON, XML, обычный текст.
- УстановитьТелоИзДвоичныхДанных(<ДвоичныеДанные>, <Content-Type>) — для отправки файлов, картинок, бинарных протоколов.
- УстановитьТелоИзПотока(<ПотокЧтения>, <Content-Type>) — для больших объемов данных (потоковая передача без загрузки всего в память).
Пример: Отправка JSON (REST API)
Самый частый сценарий — POST запрос с JSON-телом.
// Пример процедуры на клиенте (или на сервере без UI)
Процедура ОтправитьJSONНаСервер
// 1. Подготовка данных для отправки
СтруктураДанных = Новый Структура;
СтруктураДанных.Вставить("userId", 123);
СтруктураДанных.Вставить("action", "create_order");
СтруктураДанных.Вставить("items", Новый Массив({"Товар 1", "Товар 2"}));
// Сериализация в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON(, Истина)); // Истина = читаемый формат (с отступами)
ЗаписатьJSON(ЗаписьJSON, СтруктураДанных);
JSONСтрока = ЗаписьJSON.Закрыть;
// 2. Настройка соединения (HTTPS требует защищенное соединение)
// Для работы с HTTPS на сервере 1С может потребоваться настройка сертификатов (ca-certificates)
Соединение = Новый HTTPСоединение(
"api.example.com", // Хост
443, // Порт (443 для HTTPS)
, , , // Пользователь, Пароль, Прокси (если нужны)
30, // Таймаут в секундах
Новый ЗащищенноеСоединениеOpenSSL // Для HTTPS
);
// 3. Формирование запроса
Запрос = Новый HTTPЗапрос("/v1/orders");
Запрос;Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.Заголовки.Вставить("Accept", "application/json");
// Авторизация (если нужна Bearer токен)
// Запрос.Заголовки.Вставить("Authorization", "Bearer " + ВашТокен);
// 4. УСТАНОВКА ТЕЛА ЗАПРОСА
Запрос.УстановитьТелоИзСтроки(JSONСтрока, КодировкаТекста.UTF8, "application/json");
// 5. Отправка (POST)
Попытка
Результат = Соединение.ОтправитьДляОбработки(Запрос); // Асинхронно (только клиент)
// ИЛИ синхронно (на сервере и клиенте):
// Результат = Соединение.Выполнить(Запрос); // Для POST используйте Выполнить или Получить с методом POST
// Внимание: Метод Получить всегда делает GET. Для POST используйте:
Результат = Соединение.Выполнить(Запрос); // В новых версиях платформы
// В старых версиях (8.2, ранние 8;3) для POST использовали недокументированные способы или COM,
// но современный способ: Соединение.Выполнить(Запрос) где Запрос уже содержит тело -> платформа сама делает POST.
// Проверка результата
Если Результат.КодСостояния = 200 ИЛИ Результат.КодСостояния = 201 Тогда
ОтветСтрока = Результат.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
Сообщить("Успешно: " + ОтветСтрока);
Иначе
Сообщить("Ошибка HTTP: " + Результат.КодСостояния + " ⎯ " + Результат.ПолучитьТелоКакСтроку);
КонецЕсли;
Исключение
Сообщить("Ошибка связи: " + ОписаниеОшибки);
КонецПопытки;
КонецПроцедуры
> Важно: В современных версиях платформы (8.3.18+) метод HTTPСоединение.Выполнить(HTTPЗапрос) автоматически определяет метод (GET/POST/PUT) по наличию тела в запросе. Если тело есть — отправляется POST (или PUT/PATCH, если задано свойство Запрос.Метод = "PUT").
Пример: Отправка файла (multipart/form-data)
Для загрузки файлов стандартный HTTPЗапрос не имеет встроенного сборщика multipart. Нужно формировать тело вручную или использовать сторонние библиотеки (например, OneHttp). Пример ручного формирования:
Процедура ОтправитьФайлMultipart
Граница = "----WebKitFormBoundary" + СтрЗаменить(Новый УникальныйИдентификатор, "-", "");
Поток = Новый ЗаписьТекста(Новый ПотокВПамяти, КодировкаТекста.UTF8);
// Часть 1: обычное поле
Поток.ЗаписатьСтроку("--" + Граница);
Поток.ЗаписатьСтроку("Content-Disposition: form-data; name=""description""");
Поток.ЗаписатьСтроку("Content-Type: text/plain; charset=utf-8");
Поток.ЗаписатьСтроку("");
Поток.ЗаписатьСтроку("Описание моего файла");
// Часть 2: файл
Поток.ЗаписатьСтроку("--" + Граница);
Поток.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""test.txt""");
Поток.ЗаписатьСтроку("Content-Type: text/plain");
Поток.ЗаписатьСтроку("");
// Получаем двоичные данные заголовков
ДвоичныеЗаголовки = Поток.Поток.ПолучитьДвоичныеДанные;
// Читаем файл
ДанныеФайла = ПолучитьДвоичныеДанныеИзФайла("C: emp est.txt");
// Закрывающая граница
КонецТела = ПолучитьДвоичныеДанныеИзСтроки(Символы.ПС + "--" + Граница + "--" + Символы.ПС, КодировкаТекста.UTF8);
// Собираем всё в один поток/двоичные данные
Запрос = Новый HTTPЗапрос("/upload");
// ... отправка через Соединение.Выполнить(Запрос)
КонецПроцедуры
1С выступает в роли HTTP-сервиса (Чтение тела входящего запроса)
Это сценарий публикации HTTP-сервисов (расширение конфигурации `HTTPСервисы`) или REST-интерфейса. Код выполняется на сервере 1С (в контексте сеанса веб-сервиса).
Где доступен запрос?
В модуле менеджера HTTP-сервиса (или модуле объекта REST) доступен параметр Запрос типа HTTPЗапросВходящий.
Чтение тела как строки (JSON, XML, Text)
Метод ПолучитьТелоКакСтроку считывает весь поток в память. Подходит для небольших и средних запросов (до десятков МБ).
// Функция обработки POST запроса в модуле HTTP-сервиса
Функция ОбработатьЗаказ(Запрос, Ответ)
// 1. Проверка метода
Если Запрос.Метод <> "POST" Тогда
Ответ.КодСостояния = 405; // Method Not Allowed
Ответ.УстановитьТелоИзСтроки("Метод не поддерживается");
Возврат;
КонецЕсли;
// 2. Проверка Content-Type (опционально, но рекомендуется)
ContentType = Запрос.Заголовки.Получить("Content-Type");
ЕстьJSON = (ContentType <> Неопределено) И (Найти(ContentType, "application/json") > 0);
// 3. Чтение тела
Попытка
// Важно: Поток можно прочитать ТОЛЬКО ОДИН РАЗ!
ТелоСтроки = Запрос.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
Исключение
Ответ.КодСостояния = 400;
Ответ.УстановитьТелоИзСтроки("Ошибка чтения тела: " + ОписаниеОшибки);
Возврат;
КонецПопытки;
Если ПустаяСтрока(ТелоСтроки) Тогда
Ответ.КодСостояния = 400;
Ответ.УстановитьТелоИзСтроки("Пустое тело запроса");
Возврат;
КонецЕсли;
// 4. Парсинг JSON
Если ЕстьJSON Тогда
Попытка
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТелоСтроки);
ДанныеЗаказа = ПрочитатьJSON(ЧтениеJSON); // В структуру/массив/значение
// Бизнес-логика: СоздатьЗаказ(ДанныеЗаказа)...
IDЗаказа = СоздатьЗаказВБД(ДанныеЗаказа);
Ответ.КодСостояния = 201;
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Ответ.УстановитьТелоИзСтроки("{"orderId": " + IDЗаказа + ", "status": "created"}");
Исключение
Ответ.КодСостояния = 400;
Ответ.УстановитьТелоИзСтроки("Неверный JSON: " + ОписаниеОшибки);
КонецПопытки;
Иначе
// Обработка XML, form-data и т.д.
Ответ.КодСостояния = 415; // Unsupported Media Type
Ответ.УстановитьТелоИзСтроки("Поддерживается только application/json");
КонецЕсли;
КонецФункции
Потоковое чтение (Для больших файлов / экономии памяти)
Если ожидаются большие загрузки (десятки/сотни МБ), чтение в строку вызовет переполнение памяти; Используйте ПолучитьТелоКакПотокЧтения.
Функция ЗагрузитьБольшойФайл(Запрос, Ответ)
// Получаем поток чтения (не загружает всё в ОЗУ)
ПотокЧтения = Запрос.ПолучитьТелоКакПотокЧтения;
// Определяем имя файла из заголовков (Content-Disposition) или генерируем
ИмяФайла = ПолучитьИмяФайлаИзЗаголовков(Запрос.Заголовки);
ПутьХранения = КаталогВременныхФайлов + ИмяФайла;
// Записываем поток в файл по кускам (буферизированно)
ЗаписьДвоичных = Новый ЗаписьДвоичныхДанных(ПутьХранения);
Буфер = Новый ДвоичныеДанные(1024 * 1024); // Буфер 1 МБ
Пока ПотокЧтения.Прочитать(Буфер) > 0 Цикл
ЗаписьДвоичных.Записать(Буфер);
КонецЦикла;
ЗаписьДвоичных.Закрыть;
ПотокЧтения.Закрыть; // Обязательно закрываем входящий поток
// Дальше работаем с файлом ПутьХранения (перемещаем в хранилище, регистрируем в ИБ и т.д.)
Ответ.КодСостояния = 200;
Ответ.УстановитьТелоИзСтроки("Файл загружен: " + ИмяФайла);
КонецФункции
Обработка multipart/form-data (Загрузка файлов через формы)
Платформа 1С не имеет встроенного парсера multipart для входящих запросов. Вам придется парсить поток вручную или использовать готовые решения (библиотеки).
Алгоритм ручного парсинга:
- Получить `boundary` из заголовка `Content-Type` (например: `multipart/form-data; boundary=—-WebKitFormBoundaryABC123`).
- Получить поток: `Поток = Запрос.ПолучитьТелоКакПотокЧтения;`.
- Читать поток построчно/по байтам, искать разделитель `—boundary`.
- Парсить заголовки каждой части (Content-Disposition, Content-Type).
- Вычитывать тело части в файл или строку до следующего разделителя.
Рекомендация: Используйте проверенные открытые библиотеки (например, модуль `MultipartParser` из проекта oscript-library/http-client адаптированный для 1С, или аналогичные решения на Инфостарте), чтобы не изобретать велосипед и корректно обрабатывать кодировки и переносы строк.
Типичные ошибки и лучшие практики
| Проблема | Причина | Решение |
|---|---|---|
| Пустое тело на сервере | Поток `Запрос.ПолучитьТелоКакСтроку` или `ПолучитьТелоКакПотокЧтения` можно прочитать только один раз. Если вызвали дважды — второй раз будет пусто. | Читайте тело в переменную сразу при входе в функцию и работайте с переменной. |
| Кривые кириллица / кодировка | Клиент прислал в UTF-8, а сервер прочитал в ANSI (или наоборот). Заголовок `Content-Type` не содержит `charset`. | Явно указывайте `КодировкаТекста.UTF8` в `ПолучитьТелоКакСтроку(КодировкаТекста.UTF8)`. На клиенте всегда ставьте `charset=utf-8` в заголовке. |
| Ошибка «Connection reset» / Timeout на клиенте | Сервер долго обрабатывает запрос, а клиент разорвал соединение по таймауту (по умолчанию часто 30-60 сек). | Увеличьте таймаут в `HTTPСоединение` (последний параметр конструктора). Для долгих операций используйте асинхронный паттерн: вернуть 202 Accepted + ID задачи, клиент опрашивает статус. |
| 413 Payload Too Large | Веб-сервер (IIS/Apache/Nginx) или платформа 1С обрезают большие тела. | Настройте `maxAllowedContentLength` (IIS), `client_max_body_size` (Nginx), `LimitRequestBody` (Apache). В 1С (web-сервер) лимиты настраиваются в `default.vrd` (` |
| Метод GET с телом | Стандарт HTTP не запрещает тело у GET, но многие прокси/файрволы его отбрасывают. | Для передачи сложных фильтров используйте POST (в теле JSON с фильтрами) или передавайте параметры в Query String (URL). |
Резюме: Шпаргалка по методам
Клиент (Исходящий запрос: HTTPЗапрос)
- Запрос.УстановитьТелоИзСтроки(Строка, Кодировка, ContentType) — JSON, XML, Text.
- Запрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанные, ContentType) — Файлы, бинарные данные.
- Запрос.УстановитьТелоИзПотока(ПотокЧтения, ContentType) — Большие данные без копирования в память.
- Запрос.Метод = «POST» / «PUT» / «PATCH» / «DELETE» — Явная установка метода (если автоопределение не срабатывает).
- Соединение.Выполнить(Запрос) — Универсальный метод отправки (синхронный).
Сервер (Входящий запрос: HTTPЗапросВходящий)
- Запрос.ПолучитьТелоКакСтроку(Кодировка) — Прочитать всё в строку (малые/средние данные).
- Запрос.ПолучитьТелоКакДвоичныеДанные — Прочитать всё в двоичные данные.
- Запрос.ПолучитьТелоКакПотокЧтения — Получить поток для поточной обработки (большие файлы).
- Запрос.Заголовки.Получить(«Content-Type») — Определение формата данных.
- Запрос.Метод — «GET», «POST», «PUT» и т.д.
Совет: При разработке интеграций всегда логируйте входящие заголовки и первые 100- тела (если это не секретные данные) в регистрацию 1С или внешнюю систему логирования (ELK, Grafana Loki). Это экономит часы отладки при ошибках «у клиента не работает».