Как получить параметры POST-запроса в HTTP-сервисе 1С:Предприятие

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

При интеграции 1С с внешними сайтами, мобильными приложениями и сторонними сервисами разработчики часто сталкиваются с необходимостью создания HTTP-сервисов. Если при обработке GET-запросов параметры легко передаются в строке URL и считываются платформой автоматически, то при переходе к POST-запросам у многих возникают трудности. Разработчики нередко пытаются использовать те же механизмы маршрутизации, что и для GET, из-за чего получают ошибки сопоставления URL (например, код ответа 404) или не понимают, как извлечь переданные клиентом данные. В этой статье мы подробно разберем, как правильно спроектировать HTTP-сервис для приема POST-запросов, как считывать параметры из тела запроса в различных форматах и как настроить полноценную отладку, чтобы не писать код «вслепую».

Почему возникает ошибка 404 при обработке 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 или универсальный вариант /* (где символ звездочки означает сопоставление с любым подпутем).

Вариант 1. Получение параметров в формате JSON (Рекомендуемый стандарт)

Передача структурированных данных в формате 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);
    Ответ.УстановитьТелоИзСтроки("Авторизация выполнена успешно");
    Возврат Ответ;
    
КонецФункции

Вариант 2. Обработка URL-закодированных параметров (application/x-www-form-urlencoded)

Этот формат традиционно используется стандартными 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);
    Ответ.УстановитьТелоИзСтроки("Данные успешно получены");
    Возврат Ответ;
    
КонецФункции

Вариант 3. Парсинг Multipart/form-data (данные формы с разделителями)

Формат 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 передаются большие бинарные файлы, чтение тела как строки методом ПолучитьТелоКакСтроку() может привести к повреждению данных (из-за преобразования байтов в символы в определенной кодировке) и вызвать переполнение оперативной памяти сервера. В этих сценариях необходимо считывать тело как двоичный поток через Запрос.ПолучитьТелоКакПоток() и обрабатывать его с помощью объекта ЧтениеДанных.

Как настроить полноценную отладку POST-запросов (без работы «вслепую»)

Утверждение о том, что отлаживать в 1С можно только GET-запросы, так как их легко запустить из адресной строки браузера — это миф. Вы можете легко перехватывать и отлаживать входящие POST-запросы из внешних источников на точках останова в Конфигураторе. Для этого выполним следующие шаги:

  1. Включим отладку на сервере 1С: Если ваша база работает в клиент-серверном режиме, служба сервера 1С:Предприятия должна быть запущена с флагом отладки. В реестре Windows в параметрах запуска службы проверьте наличие ключа -debug (или -debug -http для HTTP-протокола отладки).
  2. Разрешим отладку при публикации: При публикации базы через Конфигуратор (меню Администрирование -> Публикация на веб-сервере...) на вкладке "Основные" обязательно установим галочку "Разрешить отладку" и укажем адрес отладчика (например, IP-адрес вашего рабочего компьютера с указанием порта отладки http://192.168.1.100:1560).
  3. Настроим автоматическое подключение предметов отладки: В Конфигураторе откроем меню Отладка -> Подключение.... Нажмем кнопку "Настройка автоматического подключения" и установим флажок напротив пункта "Web-сервер: HTTP-сервисы". Это заставит конфигуратор автоматически захватывать фоновые сеансы веб-сервера, обрабатывающие запросы.
  4. Используем Postman для отправки тестовых POST-запросов: Установим бесплатную утилиту Postman на рабочий компьютер. В интерфейсе Postman выберем метод POST, укажем полный URL опубликованного сервиса, перейдем на вкладку Body, переключим в режим raw, выберем формат JSON и напишем тестовые параметры авторизации. Поставим точку останова на первой строчке нашей функции в 1С и нажмем в Postman кнопку Send. 1С перехватит этот запрос, и вы сможете детально изучить структуру объекта Запрос во встроенном табло.

Использование связки 1С и утилиты Postman позволит вам тестировать любые сценарии интеграции быстро, удобно и без необходимости писать отладочный код вслепую.

← На главную