При интеграции 1С с внешними веб-сервисами программисты часто сталкиваются с ситуацией, когда простейший GET-запрос возвращает ошибки 404 Not Found или 401 Unauthorized. Несмотря на наличие документации к API, нюансы реализации протокола HTTP в самой платформе 1С и требования стандартов кодирования могут запутать даже опытного разработчика. В этой статье мы подробно разберем, как правильно разделять адрес сервера и ресурс, как работать с защищенным соединением и как корректно формировать заголовки авторизации.
Проанализируем ситуацию, с которой столкнулся автор темы. В коде была допущена критическая ошибка в объектах HTTPСоединение и HTTPЗапрос. Платформа 1С требует четкого разделения хоста (домена) и пути к конкретному методу API.
Рассмотрим, как делать нельзя:
СоединениеHHTP = Новый HTTPСоединение("master.dsf.ac-test.nl/api"); // Ошибка: путь в домене
HTTPЗапрос = Новый HTTPЗапрос;
HTTPЗапрос.АдресРесурса = "https://master.dsf.ac-test.nl/api/brand"; // Ошибка: полный URL вместо пути
Выясним причину ошибки: когда вы указываете полный URL в АдресРесурса, 1С передает его серверу целиком. Сервер (в данном примере на базе Yii2) получает запрос вида GET /api/https://master.dsf.ac-test.nl/api/brand. Естественно, маршрутизатор сервера не может найти такой путь и возвращает ошибку 404. Стек ошибки yii\base\InvalidRouteException: Unable to resolve the request прямо указывает на то, что сервер пытается интерпретировать протокол и домен как часть внутреннего пути приложения.
Правильный подход:
HTTPСоединение передаем только доменное имя (без http/https и без слешей).HTTPЗапрос.АдресРесурса передаем только путь, начинающийся от корня сайта (со знака /).Разберем исправленный пример:
ИмяСервера = "master.dsf.ac-test.nl";
ПутьКРесурсу = "/api/brand";
Соединение = Новый HTTPСоединение(ИмяСервера);
Запрос = Новый HTTPЗапрос(ПутьКРесурсу);
Если API работает по протоколу HTTPS, простого указания порта 443 недостаточно. В 1С необходимо явно инициализировать защищенное соединение. Рассмотрим подробнее, как это сделать. Если мы проигнорируем этот шаг, запрос может либо вообще не уйти, либо завершиться ошибкой на уровне сокетов.
Для активации SSL/TLS используем объект ЗащищенноеСоединениеOpenSSL. Посмотрим на пример кода:
Защита = Новый ЗащищенноеСоединениеOpenSSL();
Соединение = Новый HTTPСоединение("master.dsf.ac-test.nl", 443, , , , , Защита);
Использование этого объекта позволяет 1С корректно обработать сертификаты сервера и установить шифрованный канал связи.
Даже после исправления адреса ресурса часто возникает ошибка 401 Unauthorized. Рассмотрим причину: стандарт RFC 7617 жестко регламентирует, как именно должны передаваться учетные данные в методе Basic Access Authentication.
Посмотрим на ошибку автора: он кодировал логин и пароль по отдельности, а затем соединял их двоеточием. Это в корне неверно. Стандарт требует следующей последовательности действий:
Логин:Пароль.Basic (с пробелом) перед результатом.Проанализируем ситуацию с кодировками. В 1С 8.3 крайне важно, чтобы перед кодированием в Base64 строка была переведена в последовательность байтов в кодировке UTF-8. Если использовать стандартные строковые функции без учета кодировки, авторизация может не пройти, если в пароле используются специальные символы.
Рассмотрим правильный алгоритм формирования заголовка в 1С:
Логин = "admin";
Пароль = "password123";
СтрокаАвторизации = Логин + ":" + Пароль;
// Преобразуем строку в двоичные данные UTF-8
ДвоичныеДанные = УстановитьДвоичныеДанныеИзСтроки(СтрокаАвторизации, КодировкаТекста.UTF8);
// Кодируем в Base64
ЗначениеBase64 = Base64Строка(ДвоичныеДанные);
// Убираем возможные переносы строк (1С может их добавлять в Base64)
ЗначениеBase64 = СтрЗаменить(ЗначениеBase64, Символы.ПС, "");
ЗначениеBase64 = СтрЗаменить(ЗначениеBase64, Символы.ВК, "");
HTTPЗапрос.Заголовки.Вставить("Authorization", "Basic " + ЗначениеBase64);
Вы можете заметить, что конструктор HTTPСоединение имеет параметры Пользователь и Пароль. Рассмотрим, почему опытные разработчики часто предпочитают задавать заголовок Authorization вручную.
При использовании параметров конструктора 1С работает по следующей схеме:
WWW-Authenticate.Многие современные API (особенно RESTful сервисы) в целях безопасности или упрощения архитектуры не присылают заголовок WWW-Authenticate или требуют наличия заголовка Authorization сразу в первом же запросе. В этом случае "автоматическая" авторизация 1С не сработает, и вы будете постоянно получать код 401. Ручная установка заголовка гарантирует, что данные будут переданы сразу.
Суммируем все вышесказанное и составим эталонный пример функции для выполнения запроса к сайту:
Функция ВыполнитьЗапросКAPI(Логин, Пароль) Экспорт
Сервер = "master.dsf.ac-test.nl";
Ресурс = "/api/brand";
// 1. Настройка защищенного соединения
Защита = Новый ЗащищенноеСоединениеOpenSSL();
// 2. Создание соединения (порт 443 для HTTPS)
Попытка
Соединение = Новый HTTPСоединение(Сервер, 443, , , , 30, Защита);
Исключение
Сообщить("Ошибка при установке соединения: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
// 3. Формирование запроса
Запрос = Новый HTTPЗапрос(Ресурс);
// 4. Формирование заголовка авторизации по стандарту RFC 7617
ПолнаяСтрокаАвторизации = Логин + ":" + Пароль;
ДанныеАвторизации = УстановитьДвоичныеДанныеИзСтроки(ПолнаяСтрокаАвторизации, КодировкаТекста.UTF8);
Base64Авторизация = Base64Строка(ДанныеАвторизации);
// Очистка от служебных символов Base64
Base64Авторизация = СтрЗаменить(СтрЗаменить(Base64Авторизация, Символы.ПС, ""), Символы.ВК, "");
Запрос.Заголовки.Вставить("Authorization", "Basic " + Base64Авторизация);
Запрос.Заголовки.Вставить("Accept", "application/json"); // Обычно API этого требует
// 5. Выполнение запроса
Попытка
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
Возврат Ответ.ПолучитьТелоКакСтроку();
Иначе
Сообщить("Сервер вернул ошибку: " + Ответ.КодСостояния);
Сообщить("Тело ответа: " + Ответ.ПолучитьТелоКакСтроку());
Возврат Неопределено;
КонецЕсли;
Исключение
Сообщить("Ошибка при выполнении запроса: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Если вы все равно получаете ошибки, воспользуйтесь следующими советами:
//api/brand). Некоторые веб-серверы крайне чувствительны к этому.Ответ.ПолучитьТелоКакСтроку() при возникновении ошибок.Соблюдение этих правил позволит вам избежать большинства проблем при работе с внешними API и сделает ваш код интеграции надежным и соответствующим стандартам.