При интеграции 1С с внешними сайтами, мобильными приложениями и сторонними сервисами разработчики часто сталкиваются с необходимостью создания HTTP-сервисов. Если при обработке GET-запросов параметры легко передаются в строке URL и считываются платформой автоматически, то при переходе к POST-запросам у многих возникают трудности. Разработчики нередко пытаются использовать те же механизмы маршрутизации, что и для GET, из-за чего получают ошибки сопоставления URL (например, код ответа 404) или не понимают, как извлечь переданные клиентом данные. В этой статье мы подробно разберем, как правильно спроектировать HTTP-сервис для приема POST-запросов, как считывать параметры из тела запроса в различных форматах и как настроить полноценную отладку, чтобы не писать код «вслепую».
Рассмотрим типичную ошибку проектирования. Для GET-запроса авторизации разработчики часто создают шаблон URL вида /Authorization/{Login}/{Password}. В этом случае параметры передаются непосредственно в адресе ресурса, например: http://server/base/hs/my_service/Authorization/my_login/my_password. Платформа 1С успешно сопоставляет этот путь с шаблоном и помещает значения в коллекцию Запрос.ПараметрыURL.
Однако для метода POST передача конфиденциальных данных (таких как логин и пароль) в открытом виде в строке URL является грубым нарушением стандартов безопасности. POST-запрос предполагает, что все параметры передаются внутри тела (body) запроса, а сам URL должен оставаться статичным, например: http://server/base/hs/my_service/Authorization. Если при этом в настройках HTTP-сервиса в 1С для шаблона URL оставить маску /{Login}/{Password}, то при попытке отправить POST-запрос на чистый адрес без параметров в строке платформа вернет ошибку 404 (Ресурс не найден). 1С просто не сможет сопоставить входящий URL с шаблоном, так как в нем отсутствуют обязательные сегменты пути.
Правило маршрутизации POST-запросов: Шаблон URL для POST-запроса должен быть максимально простым и статичным (без фигурных скобок). Используйте шаблоны вида /Authorization или универсальный вариант /* (где символ звездочки означает сопоставление с любым подпутем).
Передача структурированных данных в формате JSON в теле POST-запроса — самый популярный и современный способ интеграции. Клиент отправляет POST-запрос, указывает в заголовках Content-Type: application/json, а в тело запроса помещает JSON-строку.
Давайте посмотрим, как легко и элегантно можно распарсить такие данные в 1С с помощью встроенных механизмов работы с JSON. Разберем пример кода обработчика запроса:
Функция AuthorizationPOST(Запрос)
// Получаем тело запроса в виде строки
ТелоСтрока = Запрос.ПолучитьТелоКакСтроку();
// Инициализируем чтение JSON
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТелоСтрока);
Попытка
// Преобразуем JSON в Структуру или Соответствие 1С
ДанныеЗапроса = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Исключение
ЧтениеJSON.Закрыть();
// В случае некорректного JSON возвращаем ошибку клиента 400 Bad Request
Ответ = Новый HTTPСервисОтвет(400);
Ответ.УстановитьТелоИзСтроки("Ошибка разбора JSON-данных!");
Возврат Ответ;
КонецПопытки;
// Извлекаем нужные параметры из структуры
Логин = "";
Пароль = "";
Если ТипЗнч(ДанныеЗапроса) = Тип("Структура") Тогда
ДанныеЗапроса.Свойство("Login", Логин);
ДанныеЗапроса.Свойство("Password", Пароль);
КонецЕсли;
// Здесь выполняем бизнес-логику (например, проверку авторизации)
// ...
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки("Авторизация выполнена успешно");
Возврат Ответ;
КонецФункции
Этот формат традиционно используется стандартными HTML-формами на сайтах. В этом случае тело запроса представляет собой строку, аналогичную GET-параметрам: Login=MyLogin&Password=MyPassword. В заголовке запроса передается Content-Type: application/x-www-form-urlencoded.
Для обработки таких данных в 1С нам потребуется считать тело запроса, раскодировать его (так как спецсимволы и пробелы заменяются на URL-коды, например %20) и разбить на пары «ключ-значение». Рассмотрим, как это реализовать:
Функция AuthorizationPOST(Запрос)
ТелоСтрока = Запрос.ПолучитьТелоКакСтроку();
// Декодируем строку, возвращая спецсимволы в исходное состояние
ДекодированноеТело = РаскодироватьСтроку(ТелоСтрока, СпособКодированияСтроки.КодировкаURL);
// Разделяем строку по символу "&" на отдельные параметры
ПараметрыМассив = СтрРазделить(ДекодированноеТело, "&");
ПараметрыСтруктура = Новый Структура;
Для Каждого СтрокаПараметра Из ПараметрыМассив Цикл
// Разделяем каждую пару на Имя и Значение
Части = СтрРазделить(СтрокаПараметра, "=");
Если Части.Количество() = 2 Тогда
ПараметрыСтруктура.Вставить(Части[0], Части[1]);
КонецЕсли;
КонецЦикла;
// Извлекаем логин и пароль
Логин = "";
Пароль = "";
ПараметрыСтруктура.Свойство("Login", Логин);
ПараметрыСтруктура.Свойство("Password", Пароль);
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки("Данные успешно получены");
Возврат Ответ;
КонецФункции
Формат multipart/form-data используется, когда наряду с текстовыми параметрами через форму передаются двоичные данные (например, файлы картинок или документов). Тело такого запроса разделено специальными уникальными строками-маркерами (boundary).
В платформе 1С отсутствует готовая функция для автоматического парсинга multipart/form-data в коллекцию параметров. Если вам присылают данные в таком формате, разбирать его структуру придется вручную. Проанализируем алгоритм извлечения простых текстовых параметров из multipart-тела:
Функция РазбратьMultipartТело(Запрос)
ПараметрыРезультат = Новый Структура;
// Сначала определим строку-разделитель (boundary) из заголовка Content-Type
ЗаголовокContentType = Запрос.Заголовки.Получить("Content-Type");
Если ЗаголовокContentType = Неопределено Тогда
Возврат ПараметрыРезультат;
КонецЕсли;
ПозицияРазделителя = СтрНайти(ЗаголовокContentType, "boundary=");
Если ПозицияРазделителя = 0 Тогда
Возврат ПараметрыРезультат;
КонецЕсли;
// Маркер в теле запроса всегда начинается с двух дополнительных дефисов "--"
МаркерРазделителя = "--" + Сред(ЗаголовокContentType, ПозицияРазделителя + 9);
ТелоСтрока = Запрос.ПолучитьТелоКакСтроку();
// Разделяем текст тела на блоки по маркеру
БлокиДанных = СтрРазделить(ТелоСтрока, МаркерРазделителя);
Для Каждого Блок Из БлокиДанных Цикл
// Проверяем, содержит ли блок описание метаданных параметра
Если СтрНайти(Блок, "Content-Disposition:") > 0 Тогда
// Ищем имя параметра в заголовке блока (name="Имя")
ПозицияИмени = СтрНайти(Блок, "name=""");
Если ПозицияИмени > 0 Тогда
ОстатокСтроки = Сред(Блок, ПозицияИмени + 6);
ДлинаИмени = СтрНайти(ОстатокСтроки, """") - 1;
ИмяПараметра = Лев(ОстатокСтроки, ДлинаИмени);
// Значение параметра отделяется от заголовков блока двойным переносом строки
РазделительДанных = Символы.ВК + Символы.ПС + Символы.ВК + Символы.ПС;
ПозицияДанных = СтрНайти(Блок, РазделительДанных);
Если ПозицияДанных = 0 Тогда
РазделительДанных = Символы.ПС + Символы.ПС;
ПозицияДанных = СтрНайти(Блок, РазделительДанных);
КонецЕсли;
Если ПозицияДанных > 0 Тогда
ЗначениеДанных = Сред(Блок, ПозицияДанных + СтрДлина(РазделительДанных));
// Удаляем технические пробелы и переносы строк по краям значения
ЗначениеДанных = СокрЛП(ЗначениеДанных);
// Очищаем хвосты строки от переносов
Если Прав(ЗначениеДанных, 1) = Символы.ПС Тогда
ЗначениеДанных = Лев(ЗначениеДанных, СтрДлина(ЗначениеДанных) - 1);
КонецЕсли;
Если Прав(ЗначениеДанных, 1) = Символы.ВК Тогда
ЗначениеДанных = Лев(ЗначениеДанных, СтрДлина(ЗначениеДанных) - 1);
КонецЕсли;
ПараметрыРезультат.Вставить(ИмяПараметра, ЗначениеДанных);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат ПараметрыРезультат;
КонецФункции
Важное предупреждение: Если через multipart/form-data передаются большие бинарные файлы, чтение тела как строки методом ПолучитьТелоКакСтроку() может привести к повреждению данных (из-за преобразования байтов в символы в определенной кодировке) и вызвать переполнение оперативной памяти сервера. В этих сценариях необходимо считывать тело как двоичный поток через Запрос.ПолучитьТелоКакПоток() и обрабатывать его с помощью объекта ЧтениеДанных.
Утверждение о том, что отлаживать в 1С можно только GET-запросы, так как их легко запустить из адресной строки браузера — это миф. Вы можете легко перехватывать и отлаживать входящие POST-запросы из внешних источников на точках останова в Конфигураторе. Для этого выполним следующие шаги:
-debug (или -debug -http для HTTP-протокола отладки).http://192.168.1.100:1560).Запрос во встроенном табло.Использование связки 1С и утилиты Postman позволит вам тестировать любые сценарии интеграции быстро, удобно и без необходимости писать отладочный код вслепую.