При интеграции 1С с внешними сервисами и API часто возникает задача отправки данных методом POST. Обычно это JSON-структура, которую нужно передать на сервер. Однако даже при, казалось бы, правильно составленном коде можно столкнуться с ошибками со стороны сервера. Для тех, кто только начинает осваивать эту тему, будет крайне полезен интерактивный обучающий курс по работе с HTTP-запросами, где подробно разбираются основы JSON, заголовков и методов передачи данных.
Проанализируем типичную ситуацию: код для отправки POST-запроса написан, но сервер не может его обработать и возвращает ошибку. Выясним причину и рассмотрим правильный способ отправки таких запросов, а также более современные альтернативы.
Рассмотрим первоначальный код, который приводил к ошибке. Задача — отправить POST-запрос с телом в формате JSON и получить ответ от сервера. Для этого используется COM-объект WinHttp.WinHttpRequest.5.1.
Пример кода, который не работает:
Процедура ОтправитьЗапрос()
URL = "https://адрес-сервиса/api/method";
ТелоЗапросаJSON = "{""parameter"":""value""}";
Попытка
Соединение = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
Соединение.Open("POST", URL, 0);
Соединение.Option(2, "Кириллица"); // Устанавливаем кодировку
Соединение.SetRequestHeader("Authorization", "Bearer мой_токен");
Соединение.Send(ТелоЗапросаJSON);
ОтветСервера = Соединение.ResponseText();
Сообщить(ОтветСервера);
Исключение
Сообщить("Ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
На первый взгляд, все выглядит логично: создаем объект, открываем соединение, устанавливаем заголовок авторизации и отправляем данные. Однако стоит помнить, что правильная авторизация с помощью токена (OAuth2.0) и корректная настройка заголовков — это половина успеха при работе с современными API.
В чем заключается главная ошибка? Проблема в том, что мы отправляем на сервер строку данных (ТелоЗапросаJSON), но не сообщаем ему, что это за данные. Сервер получает набор символов и не понимает, как их интерпретировать: это обычный текст, XML, JSON или что-то еще? Чтобы сервер правильно распознал и обработал тело запроса, необходимо явно указать тип контента с помощью специального HTTP-заголовка.
Разберем по шагам, как исправить ситуацию и заставить код работать корректно. Ключевой момент — добавление заголовка Content-Type.
// После строки Соединение.Send(ТелоЗапросаJSON);
КодСостояния = Соединение.Status; // Получаем код ответа (200, 400, 500 и т.д.)
ТекстОтвета = Соединение.ResponseText(); // Получаем тело ответа
Сообщить("Код состояния: " + КодСостояния);
Сообщить("Тело ответа: " + ТекстОтвета);
Этот простой шаг часто сразу указывает на причину проблемы, например, в ответе может быть написано: "Header 'Content-Type' is missing".
Content-Type со значением application/json. Также хорошей практикой является указание кодировки, обычно это UTF-8.
Добавим одну строку в наш код перед отправкой запроса:
Соединение.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
С учетом этого исправления, полный и рабочий код будет выглядеть так:
Процедура ОтправитьЗапросПравильно()
URL = "https://адрес-сервиса/api/method";
ТелоЗапросаJSON = "{""parameter"":""value""}";
Попытка
Соединение = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
Соединение.Open("POST", URL, Ложь); // Используем Ложь для синхронного запроса
// Устанавливаем ВАЖНЫЕ заголовки
Соединение.SetRequestHeader("Authorization", "Bearer мой_токен");
Соединение.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
// Отправляем данные
Соединение.Send(ТелоЗапросаJSON);
// Анализируем ответ
Если Соединение.Status = 200 Тогда // 200 - OK
ОтветСервера = Соединение.ResponseText();
Сообщить("Успех! Ответ сервера: " + ОтветСервера);
Иначе
Сообщить("Ошибка! Код состояния: " + Соединение.Status);
Сообщить("Тело ответа: " + Соединение.ResponseText());
КонецЕсли;
Исключение
Сообщить("Критическая ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Теперь сервер получит не просто строку, а строку с инструкцией, что это JSON в кодировке UTF-8, и сможет корректно ее разобрать.
Чтобы не писать каждый раз один и тот же код, удобно обернуть логику отправки запроса в универсальную функцию. Для масштабируемых систем отлично подойдет универсальный модуль с процедурами для быстрой разработки API, который позволяет легко расширять функционал взаимодействия с внешними сервисами.
// Функция для отправки HTTP-запросов через COM-объект WinHttp.
// Возвращает Структуру с полями: Успех, КодСостояния, ТекстОтвета.
//
Функция ОтправитьPOSTЗапросЧерезCOM(URL, ТелоЗапроса, Заголовки = Неопределено) Экспорт
Результат = Новый Структура("Успех, КодСостояния, ТекстОтвета", Ложь, 0, "");
Попытка
HTTP_Соединение = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
// Установка тайм-аутов (в миллисекундах)
// SetTimeouts(resolve, connect, send, receive)
HTTP_Соединение.SetTimeouts(10000, 10000, 30000, 30000); // 10, 10, 30, 30 секунд
HTTP_Соединение.Open("POST", URL, Ложь); // Ложь - синхронный вызов
// Установка заголовков из структуры
Если Заголовки <> Неопределено Тогда
Для Каждого Заголовок Из Заголовки Цикл
HTTP_Соединение.SetRequestHeader(Заголовок.Ключ, Заголовок.Значение);
КонецЦикла;
КонецЕсли;
// Отправка тела запроса
HTTP_Соединение.Send(ТелоЗапроса);
Результат.КодСостояния = HTTP_Соединение.Status;
Результат.ТекстОтвета = HTTP_Соединение.ResponseText;
// Считаем успехом коды 2xx
Если Результат.КодСостояния >= 200 И Результат.КодСостояния <= 299 Тогда
Результат.Успех = Истина;
КонецЕсли;
Исключение
Результат.ТекстОтвета = "Исключение при вызове COM-объекта: " + ОписаниеОшибки();
КонецПопытки;
Возврат Результат;
КонецФункции
// Пример вызова этой функции
Процедура ПримерИспользованияУниверсальнойФункции()
URL_API = "https://адрес-сервиса/api/method";
ТелоJSON = "{""parameter"":""value""}";
ЗаголовкиЗапроса = Новый Соответствие;
ЗаголовкиЗапроса.Вставить("Authorization", "Bearer мой_токен");
ЗаголовкиЗапроса.Вставить("Content-Type", "application/json; charset=utf-8");
РезультатЗапроса = ОтправитьPOSTЗапросЧерезCOM(URL_API, ТелоJSON, ЗаголовкиЗапроса);
Если РезультатЗапроса.Успех Тогда
Сообщить("Запрос выполнен успешно!");
Сообщить(РезультатЗапроса.ТекстОтвета);
Иначе
Сообщить("Ошибка при выполнении запроса!");
Сообщить("Код состояния: " + РезультатЗапроса.КодСостояния);
Сообщить("Ответ сервера: " + РезультатЗапроса.ТекстОтвета);
КонецЕсли;
КонецПроцедуры
Использование COM-объектов имеет ряд недостатков: зависимость от ОС Windows, необходимость регистрации компоненты и сложности с SSL. В качестве альтернативы можно рассмотреть интеграцию 1С с Google Таблицами, где наглядно показаны различия между нативным HTTP-запросом и COM-объектом.
Платформа 1С предоставляет собственные объекты (HTTPСоединение, HTTPЗапрос), которые являются предпочтительным способом для новых разработок. Хорошая заготовка интеграции 1С со сторонним приложением поможет вам быстро развернуть обмен данными, используя встроенные механизмы работы с JSON и XDTO.
Процедура ОтправитьЗапросВстроеннымиСредствами()
ИмяСервера = "адрес-сервиса"; // Без "https://"
ПутьКРесурсу = "/api/method";
ТелоЗапросаJSON = "{""parameter"":""value""}";
Попытка
// Создаем безопасное соединение с указанием тайм-аута
Соединение = Новый HTTPСоединение(ИмяСервера, 443, , , , 30, Новый ЗащищенноеСоединениеOpenSSL());
// Формируем заголовки запроса
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Заголовки.Вставить("Authorization", "Bearer мой_токен");
// Создаем сам запрос
Запрос = Новый HTTPЗапрос(ПутьКРесурсу, Заголовки);
// Устанавливаем тело запроса, явно указывая кодировку
Запрос.УстановитьТелоИзСтроки(ТелоЗапросаJSON, КодировкаТекста.UTF8);
// Отправляем запрос методом POST
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
// Анализируем ответ
Если Ответ.КодСостояния >= 200 И Ответ.КодСостояния <= 299 Тогда
ТекстОтвета = Ответ.ПолучитьТелоКакСтроку();
Сообщить("Успех! Ответ: " + ТекстОтвета);
Иначе
Сообщить("Ошибка! Код состояния: " + Ответ.КодСостояния);
Сообщить("Тело ответа: " + Ответ.ПолучитьТелоКакСтроку());
КонецЕсли;
Исключение
Сообщить("Критическая ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Преимущества этого подхода:
В итоге, хотя решение проблемы с COM-объектом заключается в добавлении одного заголовка, для новых проектов настоятельно рекомендуется использовать встроенные платформенные механизмы для работы с HTTP-запросами.