При интеграции 1С с веб-сайтами программисты часто сталкиваются с ситуацией, когда запрос, идеально работающий на локальном сервере (localhost), начинает выдавать ошибку 301 (Moved Permanently) или возвращать пустой результат при переносе на боевой хостинг. В этой статье мы подробно разберем, как правильно настроить HTTPСоединение, почему возникают перенаправления и как убедиться, что данные действительно дошли до сервера.
Код состояния 301 означает, что запрашиваемый ресурс окончательно перемещен по новому адресу. В контексте взаимодействия 1С с современными сайтами это чаще всего происходит по трем причинам:
www. в адресе или, наоборот, его отсутствия.Рассмотрим, почему это критично для 1С. Когда объект HTTPСоединение получает ответ 301, он может автоматически не последовать по новому адресу (особенно если это касается смены протокола), а даже если следует, тело POST-запроса при редиректе часто теряется в целях безопасности. Вместо того чтобы бороться с редиректами на стороне хостинга (отключать HTTPS), проанализируем, как сделать запрос сразу по верному адресу.
Для работы с защищенным соединением необходимо использовать объект ЗащищенноеСоединениеOpenSSL. Давайте посмотрим на пример правильной инициализации соединения:
// Использование защищенного соединения для избежания редиректа 301
Сервер = "esmedlab.ru";
Защита = Новый ЗащищенноеСоединениеOpenSSL();
HTTPСоединение = Новый HTTPСоединение(Сервер, 443, , , , , Защита);
В данном случае мы явно указываем порт 443 и передаем объект защиты. Это исключает необходимость сервера «перебрасывать» нас с 80-го порта, и ошибка 301 исчезнет.
Чтобы сервер PHP смог распознать переданные данные и поместить их в глобальный массив $_POST, необходимо соблюсти два условия: правильно установить заголовки и корректно сформировать тело запроса. Выясним причину, по которой данные могут не доходить: если вы отправляете строку в формате JSON, но при этом указываете Content-Type: application/x-www-form-urlencoded, PHP не сможет автоматически распарсить данные.
Разберем по шагам классический способ передачи параметров (как из HTML-формы):
&НаКлиенте
Процедура ОтправитьДанныеНаСайт()
Сервер = "esmedlab.ru";
Ресурс = "/index.php";
// 1. Создаем соединение (лучше использовать HTTPS)
HTTPСоединение = Новый HTTPСоединение(Сервер, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
// 2. Формируем заголовки.
// Для заполнения $_POST в PHP нужен именно application/x-www-form-urlencoded
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
HTTPЗапрос = Новый HTTPЗапрос(Ресурс, Заголовки);
// 3. Формируем тело запроса в формате ключ=значение
ПараметрДанные = "test_1c_data";
СтрокаЗапроса = "param=" + ПараметрДанные;
// Важно: ИспользованиеByteOrderMark.НеИспользовать исключает добавление невидимых символов в начало строки
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
// 4. Отправляем запрос
Попытка
Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Сообщить("Код состояния: " + Ответ.КодСостояния);
Сообщить("Тело ответа: " + Ответ.ПолучитьТелоКакСтроку());
Исключение
Сообщить("Ошибка связи: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Обратите внимание: в коде автора темы встречалась ошибка — двойной вызов метода ОтправитьДляОбработки. Рассмотрим ситуацию: если вы сначала вызываете метод просто так, а строкой ниже присваиваете результат его работы переменной, 1С выполнит два независимых запроса к серверу. Это лишняя нагрузка и возможные проблемы с логикой на стороне сайта. Всегда используйте один вызов.
Это самый важный концептуальный момент. Проанализируем ситуацию: программист отправляет запрос из 1С, получает ответ 200 и видит в ответе распечатку массива $_POST. Однако, открывая ту же страницу index.php в браузере (Chrome, Firefox), он видит пустой массив. Почему так происходит?
Протокол HTTP является Stateless (не сохраняющим состояние). Каждый запрос — это отдельный мир. Когда 1С отправляет данные:
$_POST данными из 1С.print_r($_POST).Когда вы через секунду обновляете страницу в браузере, вы создаете новый, совершенно другой запрос. Браузер выполняет GET-запрос, в котором нет никаких POST-данных. Сервер ничего не знает о том, что секунду назад сюда что-то присылала 1С.
Чтобы «увидеть» данные в браузере, которые прислала 1С, их нужно сохранить на стороне сервера. Рассмотрим пример PHP-кода (index.php), который записывает данные в файл:
<?php
// Получаем данные из POST
$data = isset($_POST['param']) ? $_POST['param'] : 'Данные не получены';
// Сохраняем в текстовый файл на сервере для последующей проверки
file_put_contents('log.txt', date('Y-m-d H:i:s') . " - Получено: " . $data . PHP_EOL, FILE_APPEND);
// Отвечаем 1С (это то, что придет в ПолучитьТелоКакСтроку)
echo "Сервер принял данные: " . $data;
?>
Теперь при обновлении страницы в браузере вы можете читать этот файл или просто проверять его наличие через FTP. Если же ваша задача — передать в 1С сложную структуру данных (например, JSON), то в PHP их следует читать из потока ввода:
<?php
// Если Content-Type был application/json
$json = file_get_contents('php://input');
$data = json_decode($json, true);
// Теперь данные в массиве $data
?>
Для успешной интеграции 1С с внешними сайтами придерживайтесь следующих правил:
ЗащищенноеСоединениеOpenSSL, если сайт работает на HTTPS, чтобы избежать 301-х редиректов.Content-Type. Для обычного $_POST это должен быть application/x-www-form-urlencoded.УстановитьТелоИзСтроки всегда указывайте ИспользованиеByteOrderMark.НеИспользовать.error_log(), чтобы видеть реальное состояние переменных в системных логах сервера.Соблюдение этих структурных правил позволит вам избежать большинства ошибок при работе с HTTP-протоколом в среде 1С:Предприятие.