Разработка интеграций со сторонними веб-сервисами с использованием HTTP-запросов — одна из наиболее частых задач для программиста 1С. Однако при переносе запросов из специализированных утилит (таких как Postman, Insomnia или обычный веб-браузер) в код 1С разработчики регулярно сталкиваются с проблемой: в Postman запрос отрабатывает корректно и сессия авторизуется, а в 1С сервер при каждом запросе присылает новые заголовки Set-Cookie, а авторизация сбрасывается или возвращает ошибку.
В этой статье мы подробно разберем, почему возникает такое поведение, как устроена работа с сессиями на стороне веб-серверов, как правильно передавать заголовки Content-Type и Cookie в 1С, а также как обойти сложную защиту от межсайтовой подделки запросов (CSRF / AntiForgery).
Одной из наиболее частых причин, почему бэкенд сайта отказывается принимать POST-запрос с авторизационными данными из 1С, является некорректно заполненный заголовок Content-Type. Веб-сервер жестко ожидает данные в определенном формате (например, application/x-www-form-urlencoded или multipart/form-data), и если формат не совпадает или заголовок передан с синтаксической ошибкой, сервер просто проигнорирует переданное тело запроса.
Рассмотрим классическую ошибку заполнения заголовков в 1С, с которой часто сталкиваются начинающие разработчики:
// ОШИБОЧНЫЙ ВАРЯНТ: Попытка вставить структуру внутрь метода Вставить()
Заголовки = Новый Соответствие;
Заголовки.Вставить(Новый Структура("Парам, Знч", "Content-Type", "application/x-www-form-urlencoded;charset=utf-8"));
При таком подходе платформа 1С не сможет корректно интерпретировать заголовок, и он либо уйдет в искаженном виде, либо вообще не будет отправлен. Чтобы исправить эту ошибку, необходимо передавать имя заголовка и его значение как два простых строковых параметра метода Вставить() объекта Соответствие:
// ПРАВИЛЬНЫЙ ВАРИАНТ: Прямая передача строковых ключа и значения
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
Помните, что Postman и современные браузеры «интеллектуальны» — они автоматически подставляют правильный Content-Type на основе выбранного режима формирования тела запроса (например, при переключении вкладки Body в режим x-www-form-urlencoded). В 1С всю эту работу разработчику приходится делать вручную.
Вторая и самая фундаментальная причина изменения кук — это природа работы HTTP-клиента в 1С. В браузере и Postman реализован механизм автоматического управления сессиями (так называемый Cookie Jar). Когда браузер выполняет первый GET-запрос к странице авторизации, сервер возвращает заголовки Set-Cookie. Браузер автоматически сохраняет их в свою внутреннюю базу данных и прикрепляет заголовок Cookie ко всем последующим запросам к этому домену.
Объект HTTPСоединение в 1С работает по принципу stateless (без сохранения состояния):
Новый HTTPЗапрос инициализирует абсолютно «чистый» объект, не знающий ничего о предыдущих вызовах.HTTPСоединение для нескольких вызовов, куки автоматически не переносятся между запросами.PHPSESSID или JSESSIONID), он считает каждый ваш запрос новым уникальным посетителем и генерирует новую куку сессии, возвращая её в очередном Set-Cookie.Для сохранения авторизации мы должны самостоятельно извлекать куки из полученного ответа сервера и передавать их в заголовки следующего запроса.
Просто скопировать содержимое заголовка Set-Cookie из ответа в заголовок нового запроса не получится. Сервер возвращает куки со служебной информацией, которая выглядит следующим образом:
Set-Cookie: session_id=xyz123; path=/; domain=example.com; expires=Mon, 23-Jun-2026 12:00:00 GMT; HttpOnly; Secure
В заголовок Cookie исходящего запроса нужно передавать только пары Ключ=Значение, очищенные от системных параметров времени жизни (expires), пути (path), домена (domain) и флагов безопасности (HttpOnly, Secure). На сервер должна вернуться исключительно строка вида:
Cookie: session_id=xyz123
Если кук несколько, они должны быть перечислены через точку с запятой с пробелом:
Cookie: session_id=xyz123; tracking_id=abc789
Рассмотрим пример кода, демонстрирующий базовый принцип ручного переноса кук в 1С:
// Выполняем первый запрос для получения кук сессии
Соединение = Новый HTTPСоединение("example.com", , , , , , Новый ЗащищенноеСоединениеOpenSSL());
ЗапросGET = Новый HTTPЗапрос("/auth/login");
ОтветGET = Соединение.Получить(ЗапросGET);
// Извлекаем заголовки ответа
ЗаголовкиОтвета = ОтветGET.Заголовки;
СтрокаSetCookie = ЗаголовкиОтвета.Получить("Set-Cookie");
Если СтрокаSetCookie <> Неопределено Тогда
// Простейшая очистка куки (берем все до первой точки с запятой)
ПозицияРазделителя = Найти(СтрокаSetCookie, ";");
Если ПозицияРазделителя > 0 Тогда
ЧистаяКука = Лев(СтрокаSetCookie, ПозицияРазделителя - 1);
Иначе
ЧистаяКука = СтрокаSetCookie;
КонецЕсли;
// Формируем следующий POST-запрос с авторизацией
ЗапросPOST = Новый HTTPЗапрос("/auth/login");
ЗапросPOST.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
ЗапросPOST.Заголовки.Вставить("Cookie", ЧистаяКука);
// Устанавливаем параметры авторизации в тело
ТелоЗапроса = "login=myusername&password=mypassword";
ЗапросPOST.УстановитьТелоИзСтроки(ТелоЗапроса);
ОтветPOST = Соединение.ОтправитьДляОбработки(ЗапросPOST);
// Проверяем результат авторизации...
КонецЕсли;
Если после настройки передачи кук и заголовка Content-Type вы все равно получаете ответ с кодом 200, но вместо авторизованной сессии сервер возвращает ошибку вроде "Status":"WrongAntiForgery" или пустой токен доступа, вы столкнулись с защитой от межсайтовой подделки запросов (CSRF/AntiForgery).
Этот механизм работает следующим образом:
Set-Cookie (например, под именем __RequestVerificationToken) и внедряет непосредственно в тело HTML-страницы (скрытое поле ввода формы <input type="hidden" name="__RequestVerificationToken" value="токен" />).Для успешной авторизации на таких ресурсах необходимо строго соблюдать двухэтапный сценарий:
Set-Cookie.Cookie, а токен — в тело запроса.Когда веб-сервер возвращает несколько заголовков Set-Cookie (например, одну куку для сессии, другую для защиты AntiForgery, третью для систем аналитики), платформа 1С объединяет их все в одну строку внутри соответствия HTTPОтвет.Заголовки под ключом "Set-Cookie", разделяя запятыми.
Здесь разработчиков подстерегает опасная «ловушка». Значение параметра expires содержит дату в формате HTTP, которая сама по себе содержит запятую после дня недели (например, expires=Mon, 23-Jun-2026 12:00:00 GMT). Если вы попытаетесь разделить строку кук стандартным методом СтрРазделить(СтрокаКук, ","), вы разобьете дату посередине, испортив структуру куки.
Разберем, как правильно распарсить сложную строку кук с помощью регулярных выражений, которые стали доступны в платформе 1С начиная с версии 8.3.23:
Функция ПолучитьОчищенныеКукиИзОтвета(HTTPОтвет) Экспорт
СтрокаSetCookie = HTTPОтвет.Заголовки.Получить("Set-Cookie");
Если ПустаяСтрока(СтрокаSetCookie) Тогда
Возврат "";
КонецЕсли;
// Регулярное выражение для поиска запятых-разделителей между куками,
// игнорируя запятые внутри параметров expires (после сокращений дней недели)
// Шаблон ищет запятые, за которыми НЕ следует название дня недели в дате expires
ШаблонРазделителя = ",(?!\s*(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\b)";
МассивКук = Новый Массив;
#Если Клиент Или Сервер Тогда
// Используем встроенный механизм регулярных выражений 1С (с версии 8.3.23)
// Для более старых версий платформы можно использовать COM-объект "VBScript.RegExp"
ЗапускRegExp = Новый РегулярноеВыражение(ШаблонРазделителя, Истина);
СтрокаРазделенная = ЗапускRegExp.Заменить(СтрокаSetCookie, "|");
ЧастиКук = СтрРазделить(СтрокаРазделенная, "|");
#КонецЕсли
Для Каждого СтрокаКуки Из ЧастиКук Цикл
СтрокаКуки = СокрЛП(СтрокаКуки);
// Извлекаем только левую часть до первой точки с запятой
ПозицияТочкиСЗапятой = Найти(СтрокаКуки, ";");
Если ПозицияТочкиСЗапятой > 0 Тогда
ОчищеннаяКука = Лев(СтрокаКуки, ПозицияТочкиСЗапятой - 1);
Иначе
ОчищеннаяКука = СтрокаКуки;
КонецЕсли;
Если Не ПустаяСтрока(ОчищеннаяКука) Тогда
МассивКук.Добавить(ОчищеннаяКука);
КонецЕсли;
КонецЦикла;
Возврат СтрСоединить(МассивКук, "; ");
КонецФункции
Если ваша база 1С работает под управлением операционной системы Windows и вам не хочется вручную писать сложные парсеры кук и обрабатывать редиректы, отличной альтернативой стандартному HTTPСоединение является использование системного COM-объекта WinHttp.WinHttpRequest.5.1.
Этот объект реализует полноценный веб-клиент на уровне ОС Windows, который умеет автоматически поддерживать сессию, переносить куки между последовательными запросами и самостоятельно обрабатывать перенаправления (редиректы 3xx):
// Инициализируем COM-объект (сессия будет сохраняться на протяжении жизни объекта)
WinHTTP = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
// Шаг 1: Получаем страницу авторизации (WinHTTP сохранит куки во внутреннем кэше)
WinHTTP.Open("GET", "https://example.com/auth/login", Ложь);
WinHTTP.Send();
// Шаг 2: Выполняем POST-запрос (WinHTTP автоматически прикрепит куки из первого шага)
WinHTTP.Open("POST", "https://example.com/auth/login", Ложь);
WinHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// Передаем параметры авторизации
ПараметрыАвторизации = "login=myusername&password=mypassword";
WinHTTP.Send(ПараметрыАвторизации);
// Проверяем статус ответа
КодСостояния = WinHTTP.Status;
Если КодСостояния = 200 Тогда
ТелоОтвета = WinHTTP.ResponseText;
// Мы успешно авторизовались! Дальнейшие запросы через объект WinHTTP продолжат использовать эту сессию.
КонецЕсли;
Использование WinHttpRequest значительно упрощает разработку парсеров и механизмов авторизации на сложных сайтах, минимизируя необходимость ручного контроля сетевого уровня.