Как исправить ошибку 301 и корректно передать POST-данные из 1С на PHP-сайт?

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

При интеграции 1С с веб-сайтами программисты часто сталкиваются с ситуацией, когда запрос, идеально работающий на локальном сервере (localhost), начинает выдавать ошибку 301 (Moved Permanently) или возвращать пустой результат при переносе на боевой хостинг. В этой статье мы подробно разберем, как правильно настроить HTTPСоединение, почему возникают перенаправления и как убедиться, что данные действительно дошли до сервера.

Разбор причины ошибки 301: Почему сервер «переезжает»?

Код состояния 301 означает, что запрашиваемый ресурс окончательно перемещен по новому адресу. В контексте взаимодействия 1С с современными сайтами это чаще всего происходит по трем причинам:

  1. Переход с HTTP на HTTPS: Большинство хостингов по умолчанию перенаправляют небезопасный трафик (порт 80) на защищенный (порт 443).
  2. Настройка префикса WWW: Сервер может требовать обязательного наличия www. в адресе или, наоборот, его отсутствия.
  3. Канонические URL: Веб-сервер может добавлять или убирать закрывающий слеш в конце пути к ресурсу.

Рассмотрим, почему это критично для 1С. Когда объект HTTPСоединение получает ответ 301, он может автоматически не последовать по новому адресу (особенно если это касается смены протокола), а даже если следует, тело POST-запроса при редиректе часто теряется в целях безопасности. Вместо того чтобы бороться с редиректами на стороне хостинга (отключать HTTPS), проанализируем, как сделать запрос сразу по верному адресу.

Для работы с защищенным соединением необходимо использовать объект ЗащищенноеСоединениеOpenSSL. Давайте посмотрим на пример правильной инициализации соединения:


// Использование защищенного соединения для избежания редиректа 301
Сервер = "esmedlab.ru";
Защита = Новый ЗащищенноеСоединениеOpenSSL();
HTTPСоединение = Новый HTTPСоединение(Сервер, 443, , , , , Защита);

В данном случае мы явно указываем порт 443 и передаем объект защиты. Это исключает необходимость сервера «перебрасывать» нас с 80-го порта, и ошибка 301 исчезнет.

Формирование правильного POST-запроса в 1С

Чтобы сервер 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С, но не видны в браузере?

Это самый важный концептуальный момент. Проанализируем ситуацию: программист отправляет запрос из 1С, получает ответ 200 и видит в ответе распечатку массива $_POST. Однако, открывая ту же страницу index.php в браузере (Chrome, Firefox), он видит пустой массив. Почему так происходит?

Протокол HTTP является Stateless (не сохраняющим состояние). Каждый запрос — это отдельный мир. Когда 1С отправляет данные:

  1. Создается процесс PHP на сервере.
  2. Заполняется массив $_POST данными из 1С.
  3. Выполняется код print_r($_POST).
  4. Результат (текст) отправляется обратно в 1С.
  5. Процесс PHP завершается, и все данные в памяти сервера уничтожаются.

Когда вы через секунду обновляете страницу в браузере, вы создаете новый, совершенно другой запрос. Браузер выполняет 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С с внешними сайтами придерживайтесь следующих правил:

Соблюдение этих структурных правил позволит вам избежать большинства ошибок при работе с HTTP-протоколом в среде 1С:Предприятие.

← На главную