При интеграции 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 МБ сразу наводит на мысли о лимитах на стороне приемника.
Первым делом нам нужно понять, что именно "не нравится" серверу. Стандартный объект 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) настроен так, чтобы сбрасывать соединения, если тело запроса превышает определенный лимит.
Если в качестве фронтенда вашего веб-сервиса выступает Nginx, то по умолчанию у него установлено ограничение client_max_body_size равное 1 МБ. Это магическое число и является причиной обрывов. Чтобы исправить ситуацию, выполним следующие действия:
nginx.conf или файл в директории sites-available).http, server или location (в зависимости от нужного охвата) увеличим лимит.Пример настройки в конфигурационном файле:
http {
...
client_max_body_size 10M;
...
}
После внесения изменений обязательно перезапустим службу Nginx, чтобы новые правила вступили в силу. Теперь сервер будет готов принимать пакеты большего объема.
Разберем важный технический нюанс. В попытках решить проблему разработчики часто натыкаются на параметр WinHttp.Option(16) и пытаются его изменить. Выясним, почему это не помогает. В документации Microsoft индекс 16 соответствует константе WinHttpOption_MaxResponseHeaderSize. Этот параметр отвечает исключительно за максимальный размер заголовков ответа, которые сервер присылает клиенту. Он никак не влияет на объем передаваемого тела запроса от 1С к серверу. Поэтому пытаться увеличить его для отправки больших файлов бессмысленно.
Даже если лимиты сервера позволяют принять файл, передача больших данных требует времени. Если канал связи медленный, соединение может закрыться по тайм-ауту. В объекте WinHttp предусмотрен метод SetTimeouts, который позволяет гибко настроить время ожидания. Разберем его параметры:
// SetTimeouts(Resolve, Connect, Send, Receive) в миллисекундах
// Установим 30 секунд на установку соединения и 5 минут на отправку/получение
WinHttp.SetTimeouts(30000, 30000, 300000, 300000);
Особое внимание уделим параметру SendTimeout. Если вы отправляете файл размером в несколько десятков мегабайт, стандартные 30 секунд могут истечь раньше, чем данные покинут ваш компьютер.
Рассмотрим альтернативный, более современный и надежный способ. Использование COM-объектов в 1С версии 8.3 — это наследие старых подходов. Платформа обладает мощным встроенным объектом HTTPСоединение, который лишен многих проблем внешних библиотек. Проанализируем преимущества перехода на штатный механизм:
rphost.HTTPЗапрос и ДвоичныеДанные 1С эффективнее работает с памятью при передаче тяжелых файлов.Пример реализации на штатных средствах:
Соединение = Новый HTTPСоединение("адрес-сервера.рф", , ИмяПользователя, Пароль);
Заголовок = Новый Соответствие();
Заголовок.Вставить("Content-Type", "application/xml");
// Читаем файл в двоичные данные без загрузки всего текста в память в виде строки
ФайлОтправки = Новый ДвоичныеДанные("C:\temp\bigfile.xml");
Запрос = Новый HTTPЗапрос("/api/upload", Заголовок);
Запрос.УстановитьТелоИзДвоичныхДанных(ФайлОтправки);
Попытка
Ответ = Соединение.ОтправитьДляОбъекта(Запрос);
Сообщить("Код ответа: " + Ответ.КодСостояния);
Исключение
Сообщить("Ошибка связи: " + ОписаниеОшибки());
КонецПопытки;
Подведем итог нашему разбору. Если вы столкнулись с обрывом соединения на файлах более 1 МБ, выполните следующие действия:
client_max_body_size.maxAllowedContentLength в web.config.MSXML2.ServerXMLHTTP.6.0 для серверного кода, так как он стабильнее в многопоточной среде.HTTPСоединение — это решит проблемы с типами данных и обеспечит работу кода на любой платформе.Помните, что передача больших объемов данных — это всегда риск потери пакетов или обрыва сессии, поэтому старайтесь также реализовывать механизмы сжатия (например, ZIP) перед отправкой, если это поддерживает принимающая сторона.