Как отправить POST-запрос из 1С, если сервер возвращает ошибку 500?

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

Часто при интеграции 1С с внешними веб-сервисами возникает ситуация, когда, казалось бы, правильно составленный POST-запрос возвращает непонятную ошибку 500 Internal Server Error без каких-либо пояснений в теле ответа. При этом аналогичный запрос из другого инструмента, например, из JavaScript в браузере, работает исправно. Давайте вместе разберемся, в чем может быть причина и как это исправить на конкретном примере, а для более глубокого изучения темы рекомендуем пройти интерактивный обучающий курс по работе с HTTP-запросами.

Проанализируем ситуацию: у нас есть код на 1С, который должен отправить данные на сервер, но он не работает. А также есть работающий пример на JavaScript, который успешно отправляет те же данные.

Анализ исходной проблемы: неверный формат данных

Рассмотрим первоначальный код на 1С, который приводил к ошибке.


// Переменные для примера
АдресСайта = "example.com";
АдресAPI = "/api/post";
ФайлJSON = "{""action"": ""getAllContragents"", ""secret"": ""08e09ac9dbc8e7a6205d1c0c82fdff1e""}"; // JSON в виде строки

// Код запроса
HTTPСоединение = Новый HTTPСоединение(АдресСайта);
ЗапросHTTP = Новый HTTPЗапрос(АдресAPI); 

// Устанавливаем заголовок, который предполагает отправку JSON
ЗапросHTTP.Заголовки.Вставить("Content-type", "application/json; charset=utf-8");

// А тело формируем как строку "ключ=значение"
ЗапросHTTP.УстановитьТелоИзСтроки("action=oneSActions" + "&data=" + ФайлJSON, КодировкаТекста.UTF8);
    
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(ЗапросHTTP); // Получаем HTTPОтвет.КодСостояния = 500

Ключевая ошибка здесь — несоответствие между заголовком Content-Type и форматом тела запроса. Мы сообщаем серверу, что отправляем данные в формате application/json, но на самом деле тело запроса представляет собой строку, похожую на данные веб-формы (key1=value1&key2=value2). Сервер, ожидая увидеть валидный JSON, не может разобрать полученные данные и возвращает общую ошибку 500.

Теперь посмотрим на работающий JavaScript-код. В нем для формирования данных используется объект FormData.


let f_data = new FormData();
f_data.append("action", "oneSActions");
f_data.append("data", JSON.stringify(json_data));

fetch(srv_url, {
    method: 'POST',
    body: f_data, // Отправка данных через FormData
});

Когда браузер отправляет данные, собранные через FormData, он автоматически устанавливает правильный заголовок Content-Type. В данном случае, так как файлы не передаются, это будет либо application/x-www-form-urlencoded, либо multipart/form-data. Именно этот формат и ожидает сервер.

Пошаговое решение: как заставить запрос работать

Проблема ясна: нам нужно в 1С сформировать запрос так, как это делает браузер с FormData. Для этого необходимо изменить и заголовок, и способ формирования тела запроса.

Шаг 1. Устанавливаем правильный заголовок Content-Type

Сервер ожидает данные в формате, аналогичном отправке обычной HTML-формы. Для этого используется заголовок application/x-www-form-urlencoded. Изменим эту строку в нашем коде.

Шаг 2. Корректно формируем тело запроса

Тело запроса должно быть строкой, где пары "ключ=значение" разделены амперсандом (&). У нас два параметра: action и data. Значением параметра data является строка JSON. Соберем эту конструкцию.

Для надежности и правильного формирования JSON-строки из данных 1С лучше использовать специальные объекты ЗаписьJSON, а дополнительно убедиться в корректности данных поможет проверка на заполненность обязательных полей в строке JSON.

Шаг 3. Собираем итоговый код

Теперь объединим все исправления и дополнения в финальный, работающий вариант кода на 1С.


// 1. Подготовим данные, которые будут внутри JSON
ДанныеДляJSON = Новый Структура;
ДанныеДляJSON.Вставить("action", "getAllContragents");
ДанныеДляJSON.Вставить("secret", "08e09ac9dbc8e7a6205d1c0c82fdff1e");

// 2. Преобразуем структуру 1С в строку JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ДанныеДляJSON);
СтрокаJSON = ЗаписьJSON.Закрыть();

// 3. Формируем тело запроса в формате x-www-form-urlencoded
// ВАЖНО: Если в строке JSON могут быть спецсимволы (&, =, ?), 
// ее нужно дополнительно кодировать для URL. В данном примере это опущено для простоты, 
// но в реальных задачах это может быть необходимо:
// СтрокаJSON = КодироватьСтроку(СтрокаJSON, СпособКодированияСтроки.URL);
ТелоЗапроса = "action=oneSActions" + "&data=" + СтрокаJSON;

// 4. Настраиваем и отправляем сам запрос
АдресСайта = "example.com";
АдресAPI = "/api/post";
HTTPСоединение = Новый HTTPСоединение(АдресСайта);
ЗапросHTTP = Новый HTTPЗапрос(АдресAPI); 

// Устанавливаем ПРАВИЛЬНЫЙ заголовок
ЗапросHTTP.Заголовки.Вставить("Content-type", "application/x-www-form-urlencoded; charset=utf-8");    

// Устанавливаем тело из сформированной строки
ЗапросHTTP.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8);

Попытка
    HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(ЗапросHTTP);
    
    Сообщить("Код ответа сервера: " + HTTPОтвет.КодСостояния);
    Если HTTPОтвет.КодСостояния = 200 Тогда
        Сообщить("Ответ сервера: " + HTTPОтвет.ПолучитьТелоКакСтроку());
    Иначе
        Сообщить("Текст ошибки: " + HTTPОтвет.ПолучитьТелоКакСтроку());
    КонецЕсли;
    
Исключение
    Сообщить("Ошибка при отправке HTTP-запроса: " + ОписаниеОшибки());
КонецПопытки;

После замены заголовка на application/x-www-form-urlencoded и отправки тела в виде строки "action=oneSActions&data={...}" сервер успешно примет и обработает запрос.

Что делать, если сервер все же ожидает JSON?

Для полноты картины рассмотрим, как выглядел бы код, если бы сервер действительно ожидал данные в формате application/json. Подобная структура часто встречается, когда настраивается интеграция 1С с Google Таблицами или другие современные API. В этом случае все тело запроса должно быть одной большой JSON-строкой.

Предположим, API ожидает такую структуру:


{
    "action": "oneSActions",
    "data": {
        "action": "getAllContragents",
        "secret": "08e09ac9dbc8e7a6205d1c0c82fdff1e"
    }
}

Тогда код на 1С для формирования такого запроса будет выглядеть следующим образом:


// 1. Собираем вложенную структуру данных в 1С
ВложенныеДанные = Новый Структура("action, secret", "getAllContragents", "08e09ac9dbc8e7a6205d1c0c82fdff1e");

ОбщиеДанные = Новый Структура;
ОбщиеДанные.Вставить("action", "oneSActions");
ОбщиеДанные.Вставить("data", ВложенныеДанные);

// 2. Преобразуем всю структуру в единую JSON-строку
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ОбщиеДанные);
ТелоЗапросаJSON = ЗаписьJSON.Закрыть();

// 3. Настраиваем и отправляем запрос
HTTPСоединение = Новый HTTPСоединение("example.com");
ЗапросHTTP = Новый HTTPЗапрос("/api/post"); 

// Устанавливаем заголовок для JSON
ЗапросHTTP.Заголовки.Вставить("Content-type", "application/json; charset=utf-8");    

// Устанавливаем тело, которое является валидной JSON-строкой
ЗапросHTTP.УстановитьТелоИзСтроки(ТелоЗапросаJSON, КодировкаТекста.UTF8);

HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(ЗапросHTTP);
// ... дальнейшая обработка ответа

Выводы и рекомендации

  1. Главное правило: заголовок Content-Type должен точно соответствовать формату данных в теле запроса.
  2. Если сервер возвращает ошибку 500 без подробностей, в первую очередь проверьте это соответствие.
  3. Для отладки HTTP-запросов используйте внешние инструменты, такие как Postman, SoapUI или специализированные средства, например, Swagger в 1С. Они позволяют быстро протестировать различные варианты заголовков и тел запроса.
  4. Всегда сверяйтесь с документацией по API. В ней должен быть четко прописан ожидаемый формат запросов, включая требования к безопасности, такие как получение токена авторизации RuStore с использованием RSA-подписи.
  5. При формировании JSON из данных 1С используйте встроенные объекты ЗаписьJSON и функцию ЗаписатьJSON — это гарантирует синтаксически правильный результат.

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

← На главную