Интеграция 1С с внешними веб-сервисами и сайтами посредством HTTP-запросов — одна из базовых задач разработчика. Однако при отправке данных в формате JSON методом POST многие разработчики сталкиваются с неожиданной ситуацией: скрипт-обработчик возвращает пустой массив параметров, а переданные данные бесследно исчезают. Разберем по шагам, почему возникает эта ошибка, как работает транспорт HTTP и как правильно организовать обмен данными между 1С и веб-сервером.
Рассмотрим классический пример кода 1С, формирующий структуру данных, сериализующий ее в JSON и отправляющий на веб-сервер с заголовком Content-Type: application/json:
тЗаписьJSON = Новый ЗаписьJSON;
тПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, " ", Истина);
тЗаписьJSON.УстановитьСтроку(тПараметрыJSON);
сЗаказы = Новый Структура;
массивЧегото = Новый Массив;
тДанные = Новый Структура;
тДанные.Вставить("ЧислоJSON", 100);
тДанные.Вставить("СтрокаJSON", "test");
массивЧегото.Добавить(тДанные);
сЗаказы.Вставить("xxx", массивЧегото);
ЗаписатьJSON(тЗаписьJSON, сЗаказы);
strJSON = тЗаписьJSON.Закрыть();
Соединение = Новый HTTPСоединение(ИмяСайта);
HTTPЗапрос = Новый HTTPЗапрос(ИмяСкрипта);
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
HTTPЗапрос.УстановитьТелоИзСтроки(strJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
На стороне PHP-скрипта разработчик пытается проверить переданные данные привычным способом через системные массивы:
var_dump($_POST);
var_dump($_GET);
Однако в результате выполнения сервер возвращает пустые массивы. Выясним причину такого поведения веб-сервера.
Массив $_POST в PHP автоматически заполняется только в тех случаях, когда входящий запрос отправлен с определенными типами содержимого: application/x-www-form-urlencoded или multipart/form-data. Эти заголовки соответствуют отправке стандартных HTML-форм. Если клиент отправляет заголовок Content-Type: application/json, веб-сервер не производит синтаксический разбор тела запроса на отдельные переменные формы и оставляет массив $_POST пустым.
Строка JSON передается в виде необработанного (сырого) тела запроса (payload). Соответственно, ожидать наличия данных внутри $_POST при передаче чистого JSON некорректно.
Для REST API и современной архитектуры веб-сервисов стандартным подходом является прямая передача JSON в теле запроса и его последующее чтение из входящего потока данных PHP. Рассмотрим правильный серверный код для приема данных:
// Считываем сырые данные из входного потока
$rawData = file_get_contents("php://input");
// Декодируем полученную JSON-строку в массив или объект PHP
$data = json_decode($rawData, true);
if ($data === null) {
http_response_code(400);
echo json_encode(["status" => "error", "message" => "Некорректный JSON"]);
exit;
}
// Успешный ответ
http_response_code(200);
echo json_encode(["status" => "success", "received" => $data]);
Поток php://input позволяет получить необработанные байты тела запроса независимо от заголовка Content-Type, после чего функция json_decode преобразует строку в ассоциативный массив.
Если серверную часть изменить невозможно и принимающий скрипт жестко рассчитан на использование массива $_POST, данные из 1С необходимо сформировать как параметр формы. Однако здесь важно не допустить критическую ошибку с кодированием символов.
Проанализируем шаги правильного формирования запроса:
Content-Type: application/x-www-form-urlencoded; charset=utf-8.КодироватьСтроку, иначе спецсимволы (кавычки, двоеточия, фигурные скобки, амперсанды & и знаки =) сломают структуру POST-параметров.ИмяПараметра=Значение.Посмотрим на пример реализации в 1С:
// Кодируем JSON для безопасной передачи в теле формы
ЗакодированныйJSON = КодироватьСтроку(strJSON, СпособКодированияСтроки.КодировкаURL);
ТелоЗапроса = "jsonData=" + ЗакодированныйJSON;
HTTPЗапрос = Новый HTTPЗапрос(ИмяСкрипта);
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
В этом случае на стороне PHP данные будут доступны в переменной $_POST['jsonData'], и их можно будет декодировать с помощью json_decode($_POST['jsonData'], true).
Если даже при использовании php://input входящий поток пуст, обратим внимание на следующие скрытые причины:
http:// на https:// или при отсутствии завершающего слэша в адресе скрипта), клиент платформы 1С может повторить запрос методом GET, полностью потеряв тело (payload). Всегда указывайте точный URL скрипта.HTTPСоединение шестым параметром обязательно нужно передавать объект ЗащищенноеСоединениеOpenSSL. Без этого соединение не сможет защищенно передать заголовки и тело.ПолучитьИмяВременногоФайла. Метод ОтправитьДляОбработки(HTTPЗапрос) возвращает объект HTTPОтвет, у которого можно сразу вызвать Ответ.ПолучитьТелоКакСтроку().тЗаписьJSON.ОткрытьФайл(...) и передавайте его методу HTTPЗапрос.УстановитьИмяФайлаТела(...). Это исключит переполнение оперативной памяти.