Почему WinHttp обрывает соединение при отправке больших файлов из 1С и как это исправить?

Программист IT и автоматизация бизнеса
← На главную

При интеграции 1С с внешними веб-сервисами разработчики часто сталкиваются с ситуацией, когда небольшие пакеты данных уходят без проблем, но стоит размеру файла превысить 1 МБ, как система выдает критическую ошибку: "Произошла исключительная ситуация (WinHttp.WinHttpRequest): Соединение с сервером было неожиданно прервано". Эта проблема кажется мистической, так как код остается прежним, а меняется только объем данных. В данной статье мы подробно разберем, почему это происходит, как правильно диагностировать причину и какие настройки сервера или кода помогут решить задачу.

Анализируем исходную ситуацию и код отправки

Рассмотрим типичный пример кода, который часто используется для отправки данных через COM-объект WinHttp.WinHttpRequest.5.1. На первый взгляд он выглядит абсолютно корректным:


WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
WinHttp.Option(2, "utf-8"); // Установка кодировки
WinHttp.Open("POST", Адрес, 0); // Открытие асинхронного соединения
WinHttp.SetRequestHeader("Content-type", "application/xml");

Если ЗначениеЗаполнено(ИмяПользователя) Тогда
    WinHttp.SetCredentials(ИмяПользователя, Пароль, 0);
КонецЕсли;

WinHttp.Send(ТекстЗапроса);

Проблема заключается в том, что метод Send возвращает крайне неинформативное сообщение об ошибке. Текст "Соединение неожиданно прервано" может означать что угодно: от падения сетевого интерфейса до отказа прокси-сервера. Однако жесткая привязка к размеру в 1 МБ сразу наводит на мысли о лимитах на стороне приемника.

Шаг 1: Уточняем диагностику с помощью смены библиотеки

Первым делом нам нужно понять, что именно "не нравится" серверу. Стандартный объект WinHttpRequest часто скрывает детали HTTP-ответов при возникновении транспортных ошибок. Чтобы получить более внятный ответ, попробуем заменить библиотеку на MSXML2.XMLHttp. Проанализируем, как изменится код:


// Вместо WinHttp.WinHttpRequest.5.1 используем MSXML2.XMLHttp
WinHttp = Новый COMОбъект("MSXML2.XMLHttp");
WinHttp.Open("POST", Адрес, Ложь, ИмяПользователя, Пароль);
WinHttp.Send(ТекстЗапроса);

// После выполнения мы сможем увидеть реальный код ошибки и текст ответа
Сообщить(WinHttp.Status);
Сообщить(WinHttp.ResponseText);

Именно этот шаг позволяет выявить истинную причину. В большинстве случаев вы увидите стандартную ошибку протокола HTTP: "413 Request Entity Too Large". Это означает, что веб-сервер (например, Nginx или IIS) настроен так, чтобы сбрасывать соединения, если тело запроса превышает определенный лимит.

Шаг 2: Настройка веб-сервера Nginx

Если в качестве фронтенда вашего веб-сервиса выступает Nginx, то по умолчанию у него установлено ограничение client_max_body_size равное 1 МБ. Это магическое число и является причиной обрывов. Чтобы исправить ситуацию, выполним следующие действия:

  1. Найдем файл конфигурации Nginx (обычно nginx.conf или файл в директории sites-available).
  2. В секции http, server или location (в зависимости от нужного охвата) увеличим лимит.
  3. Установим значение, соответствующее вашим максимальным файлам, например, 10 МБ.

Пример настройки в конфигурационном файле:


http {
    ...
    client_max_body_size 10M;
    ...
}

После внесения изменений обязательно перезапустим службу Nginx, чтобы новые правила вступили в силу. Теперь сервер будет готов принимать пакеты большего объема.

Шаг 3: Разбор заблуждений о WinHttp.Option(16)

Разберем важный технический нюанс. В попытках решить проблему разработчики часто натыкаются на параметр WinHttp.Option(16) и пытаются его изменить. Выясним, почему это не помогает. В документации Microsoft индекс 16 соответствует константе WinHttpOption_MaxResponseHeaderSize. Этот параметр отвечает исключительно за максимальный размер заголовков ответа, которые сервер присылает клиенту. Он никак не влияет на объем передаваемого тела запроса от 1С к серверу. Поэтому пытаться увеличить его для отправки больших файлов бессмысленно.

Шаг 4: Работа с тайм-аутами при больших объемах

Даже если лимиты сервера позволяют принять файл, передача больших данных требует времени. Если канал связи медленный, соединение может закрыться по тайм-ауту. В объекте WinHttp предусмотрен метод SetTimeouts, который позволяет гибко настроить время ожидания. Разберем его параметры:


// SetTimeouts(Resolve, Connect, Send, Receive) в миллисекундах
// Установим 30 секунд на установку соединения и 5 минут на отправку/получение
WinHttp.SetTimeouts(30000, 30000, 300000, 300000);

Особое внимание уделим параметру SendTimeout. Если вы отправляете файл размером в несколько десятков мегабайт, стандартные 30 секунд могут истечь раньше, чем данные покинут ваш компьютер.

Шаг 5: Переход на штатные средства 1С

Рассмотрим альтернативный, более современный и надежный способ. Использование COM-объектов в 1С версии 8.3 — это наследие старых подходов. Платформа обладает мощным встроенным объектом HTTPСоединение, который лишен многих проблем внешних библиотек. Проанализируем преимущества перехода на штатный механизм:

  1. Кроссплатформенность: Ваш код будет работать и на Linux-серверах 1С, где COM-объекты Windows попросту недоступны.
  2. Стабильность памяти: Штатные объекты корректно очищаются сборщиком мусора 1С, в то время как COM-объекты часто вызывают утечки памяти в процессе rphost.
  3. Поддержка потоков: При использовании HTTPЗапрос и ДвоичныеДанные 1С эффективнее работает с памятью при передаче тяжелых файлов.

Пример реализации на штатных средствах:


Соединение = Новый HTTPСоединение("адрес-сервера.рф", , ИмяПользователя, Пароль);
Заголовок = Новый Соответствие();
Заголовок.Вставить("Content-Type", "application/xml");

// Читаем файл в двоичные данные без загрузки всего текста в память в виде строки
ФайлОтправки = Новый ДвоичныеДанные("C:\temp\bigfile.xml");
Запрос = Новый HTTPЗапрос("/api/upload", Заголовок);
Запрос.УстановитьТелоИзДвоичныхДанных(ФайлОтправки);

Попытка
    Ответ = Соединение.ОтправитьДляОбъекта(Запрос);
    Сообщить("Код ответа: " + Ответ.КодСостояния);
Исключение
    Сообщить("Ошибка связи: " + ОписаниеОшибки());
КонецПопытки;

Резюме и рекомендации

Подведем итог нашему разбору. Если вы столкнулись с обрывом соединения на файлах более 1 МБ, выполните следующие действия:

Помните, что передача больших объемов данных — это всегда риск потери пакетов или обрыва сессии, поэтому старайтесь также реализовывать механизмы сжатия (например, ZIP) перед отправкой, если это поддерживает принимающая сторона.

← На главную