Как решить проблему с HTTP-запросом в 1С и исправить ошибку 404 Not Found

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

Интеграция 1С с внешними веб-сервисами, сайтами и API — одна из самых частых задач современного разработчика. Для обмена данными платформа использует встроенные механизмы работы с протоколами HTTP/HTTPS. Однако при написании кода легко совершить неочевидные ошибки, из-за которых сервер будет возвращать пустые ответы или классические ошибки маршрутизации, такие как 404 Not Found или 400 Bad Request.

В этой статье мы подробно разберем практический кейс с форума, выясним причины некорректной работы запросов и построим надежный, отказоустойчивый шаблон для работы с HTTP-запросами в 1С.

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

Рассмотрим ситуацию: у разработчика есть рабочий URL-адрес, который при вводе в адресную строку браузера возвращает корректный результат:

http://auto-motors.com.ua/1C/1C_status_item.php?signin=parol&bill[]=70171&status=9

Однако попытка реализовать этот запрос в коде 1С приводит к ошибке 404 Not Found (запрашиваемый ресурс не найден). Исходный нерабочий код выглядел следующим образом:


Сервер = "auto-motors.com.ua";
СТрокаЗапроса = "signin=parol&bill[]=70171&status=9";

Соединение = Новый HTTPСоединение(Сервер,,,,,60,Новый ЗащищенноеСоединениеOpenSSL(Новый СертификатКлиентаWindows));
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "text/html; charset=iso-8859-1");
Запрос = Новый HTTPЗапрос("/1C/", Заголовки);
Запрос.УстановитьТелоИзСтроки(СТрокаЗапроса);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
ТекстОтвета = Ответ.ПолучитьТелоКакСтроку(); 
Сообщить(ТекстОтвета);

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

Ошибка №1: Путаница между GET и POST запросами

Разберем разницу между основными методами передачи данных. Когда мы вводим адрес в строку браузера, выполняется GET-запрос. Параметры этого запроса передаются непосредственно в строке URL после вопросительного знака ?.

В исходном коде разработчик использовал метод ОтправитьДляОбработки(), который отправляет POST-запрос. При этом параметры были помещены в тело запроса с помощью метода УстановитьТелоИзСтроки(), а путь запроса был сокращен до /1C/.

Веб-сервер, настроенный на прием GET-запроса по конкретному адресу скрипта, при обращении к папке /1C/ методом POST закономерно вернул ошибку 404, так как физически по этому пути обработчик отсутствует.

Решение: Для GET-запросов все параметры должны оставаться в строке адреса, а выполнять запрос нужно методом Получить() или общим методом ВызватьHTTPМетод("GET", Запрос).

Ошибка №2: Некорректная настройка защищенного соединения SSL

Обратим внимание на инициализацию соединения:

Новый ЗащищенноеСоединениеOpenSSL(Новый СертификатКлиентаWindows)

Здесь допущены сразу две ошибки:

  1. Исходный сайт работает по протоколу HTTP (порт 80), а не HTTPS (порт 443). Использование объекта ЗащищенноеСоединениеOpenSSL принудительно заставляет 1С пытаться установить шифрованное соединение, что приводит к сбою подключения.
  2. Передача параметра Новый СертификатКлиентаWindows требуется исключительно для двусторонней (взаимной) аутентификации (mTLS), когда сервер требует от клиента персональный сертификат безопасности. Для обычных защищенных сайтов (HTTPS) достаточно передавать пустой конструктор Новый ЗащищенноеСоединениеOpenSSL().

Решение: Если целевой ресурс доступен по обычному протоколу http://, параметр защищенного соединения в конструкторе HTTPСоединение указывать не нужно.

Ошибка №3: Ведущий слэш в пути ресурса

В платформе 1С адрес ресурса в конструкторе объекта HTTPЗапрос должен обязательно начинаться с косой черты — ведущего слэша /. Например, правильно писать "/1C/1C_status_item.php...", а не "1C/1C_status_item.php...". Хотя некоторые веб-серверы могут автоматически корректировать запросы, отсутствие слэша на строгих прокси-серверах или современных версиях Apache/Nginx гарантированно вызовет ошибку маршрутизации.

Реализация правильного GET-запроса

С учетом разбора ошибок, минимальный рабочий код для решения задачи автора выглядит следующим образом:


Сервер = "auto-motors.com.ua";
// Формируем полный путь к ресурсу вместе с параметрами запроса
ПутьКРесурсу = "/1C/1C_status_item.php?signin=parol&bill[]=70171&status=9";

// Создаем обычное HTTP-соединение без SSL
Соединение = Новый HTTPСоединение(Сервер);

// Создаем запрос с указанием полного пути
Запрос = Новый HTTPЗапрос(ПутьКРесурсу);

// Отправляем GET-запрос методом Получить()
Ответ = Соединение.Получить(Запрос);

// Выводим результат
ТекстОтвета = Ответ.ПолучитьТелоКакСтроку();
Сообщить(ТекстОтвета);

Этот код лаконичен и решает поставленную задачу. Однако при интеграции с современными системами в реальных условиях эксплуатации этого может быть недостаточно. Рассмотрим лучшие практики создания надежных HTTP-запросов.

Лучшие практики и дополнительные технические нюансы

1. Обязательное кодирование параметров URL (URL Encoding)

В строке запроса автора присутствуют квадратные скобки: bill[]. Символы [ и ] являются зарезервированными. Если веб-сервер работает под управлением современных версий Apache или Nginx с жесткими правилами безопасности, неэкранированные квадратные скобки в URL могут привести к ошибке сервера 400 Bad Request.

Для предотвращения подобных ситуаций все спецсимволы, кириллицу и пробелы в значениях параметров необходимо кодировать. В 1С для этого предназначена встроенная функция КодироватьСтроку. Символы [ и ] должны преобразовываться в %5B и %5D соответственно.

Рассмотрим пример правильного кодирования параметров:


ПараметрИмя = КодироватьСтроку("bill[]", СпособКодированияСтроки.КодировкаURL);
ПараметрЗначение = КодироватьСтроку("70171", СпособКодированияСтроки.КодировкаURL);
// В результате получим: bill%5B%5D=70171

2. Автоматический разбор сложных URL с помощью БСП

Если адрес запроса хранится в базе в виде полной строки (например, в константе или справочнике) и может динамически меняться, вручную разделять его на адрес сервера и путь ресурса неудобно.

Если ваша конфигурация разработана на базе Библиотеки стандартных подсистем (БСП), используйте готовую функцию разбора URL:


ПолныйАдрес = "https://auto-motors.com.ua/1C/1C_status_item.php?signin=parol&bill[]=70171&status=9";
СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(ПолныйАдрес);

// Получаем готовые параметры для создания соединения
Сервер = СтруктураURI.Хост;
Порт = СтруктураURI.Порт;
ПутьНаСервере = СтруктураURI.ПутьНаСервере; // Сюда автоматически войдут все параметры после "?"

3. Обработка редиректов (перенаправлений 301/302)

Большинство современных сайтов используют защищенное соединение и автоматически перенаправляют пользователей с протокола http:// на https://.

Метод платформы 1С HTTPСоединение.Получить() по умолчанию не переходит по редиректам автоматически. Если сервер настроен на перенаправление, 1С вернет код состояния 301 Moved Permanently или 302 Found, а тело ответа будет пустым. Нам необходимо обрабатывать такие ситуации вручную, анализируя заголовки ответа.

Рассмотрим, как правильно написать функцию с поддержкой перенаправлений:


Функция ВыполнитьЗапросСРедиректом(Знач Сервер, Знач ПутьНаСервере, Знач ИспользоватьSSL = Ложь) Экспорт
    
    ЗащищенноеСоединение = Неопределено;
    Если ИспользоватьSSL Тогда
        ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
    КонецЕсли;
    
    Соединение = Новый HTTPСоединение(Сервер, , , , , 30, ЗащищенноеСоединение);
    Запрос = Новый HTTPЗапрос(ПутьНаСервере);
    
    Ответ = Соединение.Получить(Запрос);
    
    // Проверяем статус редиректа
    Если Ответ.КодСостояния = 301 Или Ответ.КодСостояния = 302 Тогда
        // Получаем новый адрес из заголовка "Location"
        НовыйАдрес = Ответ.Заголовки.Получить("Location");
        Если ЗначениеЗаполнено(НовыйАдрес) Тогда
            // Разбираем новый адрес с помощью БСП
            СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(НовыйАдрес);
            НовыйSSL = (СтруктураURI.Схема = "https");
            // Повторяем запрос по новому адресу
            Возврат ВыполнитьЗапросСРедиректом(СтруктураURI.Хост, СтруктураURI.ПутьНаСервере, НовыйSSL);
        КонецЕсли;
    КонецЕсли;
    
    Возврат Ответ;
КонецФункции

Универсальный шаблон отправки GET-запроса

Объединим все лучшие практики в один надежный метод, который выполняет безопасное кодирование параметров, автоматически определяет необходимость SSL и возвращает результат выполнения HTTP-запроса.


&НаСервере
Функция ОтправитьБезопасныйЗапросНаСервер()
    
    // Исходные данные
    БазовыйАдрес = "auto-motors.com.ua";
    СкриптПуть = "/1C/1C_status_item.php";
    
    // Безопасно формируем параметры запроса с URL-кодированием
    Параметры = Новый Соответствие;
    Параметры.Вставить("signin", "parol");
    Параметры.Вставить("bill[]", "70171");
    Параметры.Вставить("status", "9");
    
    СтрокаПараметров = "";
    Для Каждого Параметр Из Параметры Цикл
        СимволРазделителя = ?(ПустаяСтрока(СтрокаПараметров), "", "&");
        ИмяКод = КодироватьСтроку(Параметр.Ключ, СпособКодированияСтроки.КодировкаURL);
        ЗначениеКод = КодироватьСтроку(Параметр.Значение, СпособКодированияСтроки.КодировкаURL);
        
        СтрокаПараметров = СтрокаПараметров + СимволРазделителя + ИмяКод + "=" + ЗначениеКод;
    КонецЦикла;
    
    ПолныйПутьРесурса = СкриптПуть + "?" + СтрокаПараметров;
    
    // Инициализируем соединение. Если сайт работает по HTTPS - включаем SSL
    ИспользоватьHTTPS = Ложь; // Поменяйте на Истина, если целевой ресурс использует https://
    
    ЗащищенноеСоединение = Неопределено;
    Порт = 80;
    
    Если ИспользоватьHTTPS Тогда
        ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
        Порт = 443;
    КонецЕсли;
    
    Попытка
        Соединение = Новый HTTPСоединение(БазовыйАдрес, Порт, , , , 30, ЗащищенноеСоединение);
        Запрос = Новый HTTPЗапрос(ПолныйПутьРесурса);
        
        // Устанавливаем базовые заголовки для корректной интерпретации сервером
        Запрос.Заголовки.Вставить("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        Запрос.Заголовки.Вставить("Accept-Charset", "utf-8");
        
        Ответ = Соединение.Получить(Запрос);
        
        Если Ответ.КодСостояния = 200 Тогда
            ТекстОтвета = Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
            Возврат ТекстОтвета;
        Иначе
            ВызватьИсключение "Сервер вернул ошибку с кодом состояния: " + Ответ.КодСостояния;
        КонецЕсли;
        
    Исключение
        ЗаписьЖурналаРегистрации("Интеграция.HTTPЗапросы", УровеньЖурналаРегистрации.Ошибка, , , 
            ОписаниеОшибки());
        ВызватьИсключение "Не удалось выполнить HTTP-запрос: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
    КонецПопытки;
    
КонецФункции

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

← На главную