При интеграции 1С:Предприятия с внешними веб-сервисами и личными кабинетами через COM-объект WinHttp.WinHttpRequest.5.1 разработчики часто сталкиваются с ситуацией, когда прямое обращение к конкретному HTTP-заголовку (например, Location) вызывает ошибку времени выполнения. Разберем подробно, какими методами можно просмотреть все заголовки ответа, почему пропадает заголовок перенаправления и как правильно обрабатывать сетевые запросы.
Для чтения отдельного заголовка в объекте WinHttpRequest предназначен метод getResponseHeader(). Однако если запрашиваемого заголовка в ответе сервера нет, этот метод не возвращает пустую строку, а аварийно завершает работу с исключением. Чтобы увидеть полный список заголовков, возвращенных сервером, используем метод GetAllResponseHeaders().
Рассмотрим пример кода на платформе 1С:Предприятие 7.7, позволяющий безопасно получить и вывести все заголовки:
WinHttpReq = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
WinHttpReq.Open("POST", "https://service.fsrar.ru/auth/login", 0);
WinHttpReq.SetRequestHeader("Accept", "text/html, application/xhtml+xml, */*");
WinHttpReq.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
Попытка
WinHttpReq.Send(СтрЗапр);
// Получаем все заголовки ответа одной строкой
ВсеЗаголовки = WinHttpReq.GetAllResponseHeaders();
Сообщить("Заголовки ответа сервера:");
Сообщить(ВсеЗаголовки);
Исключение
Сообщить("Ошибка при отправке запроса или получении ответа: " + ОписаниеОшибки());
КонецПопытки;
Анализируя строку, возвращенную методом GetAllResponseHeaders(), можно точно определить, какие параметры передал сервер (например, Set-Cookie, Content-Type, Date, Server), и избежать ошибок при вызове отдельных свойств.
Выясним причину, по которой заголовок Location может отсутствовать в ответе, даже если при авторизации на сайте должен происходить переход на другую страницу. По умолчанию объект WinHttp.WinHttpRequest.5.1 автоматически следует по HTTP-редиректам (статусы 301, 302, 303, 307). В результате вы получаете ответ от конечной страницы с кодом состояния 200 OK, на которой заголовок Location уже не возвращается.
Чтобы перехватить сам статус перенаправления и извлечь URL из заголовка Location, необходимо отключить автоматический переход по редиректам с помощью специальной опции объекта.
Разберем по шагам отключение авторедиректа:
WinHttp.WinHttpRequest.5.1.Option(6) = 0 (параметр WinHttpRequestOption_EnableRedirects со значением 0 отключает автоматическое следование).Send().Status. Если код равен 302 или 301, безопасно считываем заголовок Location через getResponseHeader("Location").Посмотрим на пример реализации с отключением редиректов и безопасным чтением заголовка:
WinHttpReq = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
WinHttpReq.Open("POST", "https://service.fsrar.ru/auth/login", 0);
// Отключаем автоматический редирект (Option 6 = WinHttpRequestOption_EnableRedirects)
WinHttpReq.Option(6) = 0;
WinHttpReq.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
Попытка
WinHttpReq.Send(СтрЗапр);
// Проверяем код ответа
Если (WinHttpReq.Status = 301) Или (WinHttpReq.Status = 302) Или (WinHttpReq.Status = 303) Тогда
ПереходНаСайт = WinHttpReq.getResponseHeader("Location");
Сообщить("URL перенаправления: " + ПереходНаСайт);
Иначе
Сообщить("Редирект не обнаружен. Код ответа: " + WinHttpReq.Status);
КонецЕсли;
Исключение
Сообщить("Не удалось выполнить запрос: " + ОписаниеОшибки());
КонецПопытки;
Проанализируем дополнительные технические детали, которые критически важны для стабильной работы с внешними порталами:
WaitForResponse(): Данный метод необходим только при асинхронном режиме работы (когда третий параметр метода Open установлен в 1 или Истина). При синхронном вызове (со значением 0) метод Send() блокирует выполнение до получения ответа, поэтому вызывать WaitForResponse() не требуется.WinHttpReq.Option(9) = 2048 (параметр WinHttpRequestOption_SecureProtocols).Accept-Encoding): Если указать заголовок Accept-Encoding: gzip, deflate, сервер вернет ответ в сжатом виде. Объект WinHttpRequest не распаковывает сжатый трафик автоматически, поэтому свойство ResponseText вернет нечитаемый бинарный поток. Если встроенной распаковки нет, не передавайте данный заголовок.getResponseHeader() рекомендуется оборачивать в конструкцию Попытка ... Исключение ... КонецПопытки, чтобы исключить аварийное завершение работы модуля при отсутствии заголовка.