При программной интеграции 1С со сторонними веб-сервисами и личными кабинетами разработчики часто сталкиваются с задачей имитации действий пользователя: нужно выполнить вход под логином и паролем с помощью HTTP-запроса, сохранить сессию и скачать необходимые данные (например, отчеты или выгрузки). В процессе решения этой задачи нередко возникают ошибки 404 (Not Found) или 401 (Unauthorized). Разберем по шагам, почему они возникают и как правильно настроить процесс веб-авторизации в платформе 1С:Предприятие.
Проанализируем типичную ошибку при инициализации запроса. Если в объекте HTTPСоединение сервер уже указан, то в конструкторе HTTPЗапрос нельзя повторно передавать полный URL.
Посмотрим на пример ошибочного кода:
Соединение = Новый HTTPСоединение("lk-ofd.taxcom.ru", 443, , , Прокси, 120, ЗащищенноеСоединениеOpenSSL);
HTTPЗапрос = Новый HTTPЗапрос("https://lk-ofd.taxcom.ru/", Заголовки); // Ошибка!
При такой передаче платформа формирует итоговый путь, подставляя значение параметра запроса к адресу хоста из соединения. Сервер не находит ресурс с подобным путем и возвращает ошибку 404.
Решение: В объекте HTTPЗапрос следует указывать исключительно относительный путь относительно корня сайта:
HTTPЗапрос = Новый HTTPЗапрос("/", Заголовки);
Выясним важную деталь, касающуюся передачи логина и пароля. Конструктор HTTPСоединение содержит параметры для имени пользователя и пароля:
Новый HTTPСоединение(Сервер, Порт, Пользователь, Пароль...);
Важно помнить: эти параметры предназначены исключительно для стандартной Basic/Digest-аутентификации (когда 1С автоматически подставляет заголовок Authorization: Basic ...). Если же вы авторизуетесь через веб-форму сайта, передавая данные в теле POST-запроса (в формате application/x-www-form-urlencoded или JSON), передавать логин и пароль в конструктор HTTPСоединение не нужно. Оставьте их пустыми, иначе сервер может вернуть конфликт заголовков авторизации.
В отличие от интернет-браузеров, платформа 1С и объект HTTPСоединение не сохраняют Cookie автоматически между последовательными запросами. Утверждение, что платформа сама сохраняет сессию, ошибочно.
После отправки POST-запроса на вход сервер при успешной аутентификации обычно возвращает статус перенаправления 302 (или 200 OK) и заголовок Set-Cookie. В этом заголовке передаются идентификаторы сессии (например, ASPXAUTH, PHPSESSID, JSESSIONID).
Если для получения отчета сразу отправить GET-запрос без передачи этих данных, сервер вернет статус 401 Unauthorized, так как посчитает запрос анонимным.
Разберем правила передачи Cookie:
Set-Cookie из объекта HTTPОтвет после авторизации.path=/, expires=..., domain=..., HttpOnly, secure, SameSite). Передавать на сервер нужно только «чистые» пары вида Имя=Значение.Имя1=Значение1; Имя2=Значение2.Cookie.Нередко в коде можно встретить следующую ошибку:
Соединение.ВызватьHTTPМетод("GET", GET_Запрос, Файл);
HTTPОтвет = Соединение.Получить(GET_Запрос, Файл);
Методы ВызватьHTTPМетод(), Получить() и ОтправитьДляОбработки() являются самостоятельными методами исполнения запроса. Последовательный вызов этих методов отправляет один и тот же запрос дважды. Это может привести к сбросу сессии, блокировке или непредсказуемым ошибкам. Для отправки GET-запроса достаточно вызвать метод Получить() один раз.
Объединим все правила и рассмотрим готовый рабочий шаблон для авторизации на сайте и выполнения защищенного запроса:
// 1. Настройка защищенного соединения
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено);
Сервер = "lk-ofd.taxcom.ru";
// Создаем соединение без указания логина и пароля Basic-авторизации
Соединение = Новый HTTPСоединение(Сервер, 443, , , , 120, ЗащищенноеСоединение);
// 2. Формирование POST-запроса авторизации
ЗаголовкиАвторизации = Новый Соответствие;
ЗаголовкиАвторизации.Вставить("Content-Type", "application/x-www-form-urlencoded");
// Относительный путь к форме авторизации
HTTPЗапросВход = Новый HTTPЗапрос("/", ЗаголовкиАвторизации);
// Тело запроса с параметрами входа
ТелоСтрока = "ReturnUrl=&AccountId=12345&Email=moeimya.familiya%40adres-pochty.ru&Password=12345678";
HTTPЗапросВход.УстановитьТелоИзСтроки(ТелоСтрока, КодировкаТекста.UTF8);
HTTPОтветВход = Соединение.ОтправитьДляОбработки(HTTPЗапросВход);
// Проверяем результат (для редиректа обычно приходит код 302, для успеха - 200)
Если HTTPОтветВход.КодСостояния <> 200 И HTTPОтветВход.КодСостояния <> 302 Тогда
ВызватьИсключение "Ошибка авторизации! Код состояния: " + HTTPОтветВход.КодСостояния;
КонецЕсли;
// 3. Извлечение и подготовка Cookie
СтрокаSetCookie = HTTPОтветВход.Заголовки.Получить("Set-Cookie");
Если СтрокаSetCookie = Неопределено Тогда
ВызватьИсключение "Сервер не вернул сессионные куки!";
КонецЕсли;
// Оставляем только имя и значение куки до первого разделителя параметров
ПозицияТочкиСЗапятой = Найти(СтрокаSetCookie, ";");
Если ПозицияТочкиСЗапятой > 0 Тогда
ЧистыеКуки = Лев(СтрокаSetCookie, ПозицияТочкиСЗапятой - 1);
Иначе
ЧистыеКуки = СтрокаSetCookie;
КонецЕсли;
// 4. Формирование GET-запроса за данными с сессионными Cookie
ЗаголовкиДанных = Новый Соответствие;
ЗаголовкиДанных.Вставить("Cookie", ЧистыеКуки);
ОтносительныйПутьОтчета = "/api/report/fiscaldocument/generate?beginDate=" + Формат(ДатаНачала, "ДФ=yyyy-MM-dd") + "&endDate=" + Формат(ДатаКонца, "ДФ=yyyy-MM-dd");
HTTPЗапросДанные = Новый HTTPЗапрос(ОтносительныйПутьОтчета, ЗаголовкиДанных);
ИмяФайлаРезультата = ПолучитьИмяВременногоФайла("xlsx");
// Отправляем запрос один раз и сразу сохраняем результат в файл
HTTPОтветДанные = Соединение.Получить(HTTPЗапросДанные, ИмяФайлаРезультата);
Если HTTPОтветДанные.КодСостояния = 200 Тогда
// Файл успешно скачан и готов к обработке
Сообщить("Отчет успешно получен и сохранен во временный файл: " + ИмяФайлаРезультата);
Иначе
Сообщить("Не удалось получить отчет. Код: " + HTTPОтветДанные.КодСостояния, СтатусСообщения.Важное);
КонецЕсли;
Следуя этой структуре, мы избегаем проблем с маршрутизацией запросов и гарантируем корректную передачу сессии между вызовами в 1С.