При интеграции систем часто возникает задача передачи двоичных данных (например, PDF-документов или изображений) через веб-сервисы. Стандартным подходом является кодирование файла в строку Base64 и включение её в XML-пакет SOAP. Однако на практике разработчики часто сталкиваются с тем, что при работе с файлами большого объема (от нескольких мегабайт) строка начинает вести себя непредсказуемо: она кажется «обрезанной» в отладчике, а сервер возвращает ошибку 400 Bad Request. Разберем подробно, почему это происходит и как правильно реализовать передачу больших данных в 1С.
Рассмотрим типичную ситуацию. Разработчик получает двоичные данные файла, конвертирует их в Base64, а затем пытается собрать SOAP-сообщение простым сложением строк. Проблема заключается в том, что при работе с очень длинными строками в оперативной памяти (сотни тысяч и миллионы символов) механизм конкатенации (оператор +) становится крайне неэффективным. Это приводит к фрагментации памяти и замедлению работы системы.
Более того, отладчик 1С имеет встроенное ограничение на просмотр значений переменных: он показывает только начальную часть длинной строки. Это часто создает ложное впечатление, что строка «обрезалась», хотя в памяти объект может быть полным. Но главная опасность кроется в передаче этой строки через HTTPЗапрос.
Как показала практика обсуждения, одним из самых стабильных способов является предварительное формирование всего тела запроса в текстовом файле на диске. Это позволяет избежать проблем с динамическим выделением памяти под гигантские строки и дает возможность точно контролировать кодировку.
Разберем пошагово, как это реализовать:
ЗаписьТекста.Base64 строку непосредственно в этот файл.
// Путь к временному файлу для тела запроса
ИмяФайлаТела = КаталогВременныхФайлов() + "soap_request.xml";
// Используем ЗаписьТекста с явным указанием кодировки и БЕЗ BOM
// Это критично, так как многие веб-сервисы не принимают символ BOM (Byte Order Mark)
ТекстЗапроса = Новый ЗаписьТекста(ИмяФайлаТела, КодировкаТекста.UTF8, , , Ложь);
// Формируем заголовок SOAP
ТекстЗапроса.ЗаписатьСтроку("<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" ...>");
ТекстЗапроса.ЗаписатьСтроку("<soapenv:Body>");
ТекстЗапроса.ЗаписатьСтроку("<int:Documents>");
// Получаем Base64 данные файла
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКPDF);
СтрокаBase64 = Base64Строка(ДвоичныеДанныеФайла);
// Записываем саму строку в файл
ТекстЗапроса.Записать(СтрокаBase64);
// Закрываем тэги
ТекстЗапроса.ЗаписатьСтроку("</int:Documents>");
ТекстЗапроса.ЗаписатьСтроку("</soapenv:Body>");
ТекстЗапроса.ЗаписатьСтроку("</soapenv:Envelope>");
ТекстЗапроса.Закрыть();
// Отправляем запрос
HTTPЗапрос = Новый HTTPЗапрос(Ресурс);
HTTPЗапрос.УстановитьИмяФайлаТела(ИмяФайлаТела);
Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
Выясним причину, почему метод УстановитьТелоИзСтроки часто приводит к ошибке 400 Bad Request. По умолчанию 1С при записи строки в кодировке UTF-8 может добавлять в начало сообщения невидимую метку порядка байтов (BOM). Многие современные веб-серверы (особенно построенные на Java или строгих реализациях .NET) воспринимают эти три байта перед символом < как мусор или некорректный синтаксис XML. Использование объекта ЗаписьТекста с параметром ВыбиратьBOM = Ложь (пятый параметр конструктора) гарантирует отсутствие лишних символов в начале пакета.
Проанализируем более современный и производительный способ работы с большими данными — потоки данных. Вместо того чтобы загружать весь PDF-файл в память в виде строки Base64, мы можем использовать комбинированные потоки. Это позволяет передавать данные практически любого размера, не опасаясь переполнения RAM.
Метод HTTPЗапрос.УстановитьТелоИзПотока() является наиболее предпочтительным для высоконагруженных систем. В этом случае платформа сама управляет буферизацией при передаче данных в сокет.
Рассмотрим ситуацию, когда Base64 строка вставляется вручную через конкатенацию. Это «плохой тон» в программировании на 1С. Гораздо эффективнее использовать специализированный объект ЗаписьXML. Он умеет записывать двоичные данные в формате Base64 порциями, что значительно экономит ресурсы.
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ИмяФайлаТела, "UTF-8");
Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("soapenv:Envelope");
// ... запись других узлов
Запись.ЗаписатьНачалоЭлемента("arr:base64Binary");
// Используем встроенный метод для записи двоичных данных
ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
Запись.ЗаписатьBase64(ДвоичныеДанные);
Запись.ЗаписатьКонецЭлемента();
Запись.Закрыть();
Этот метод ЗаписатьBase64 самостоятельно преобразует байты в текстовый формат Base64 прямо в процессе записи в файл (или поток), минуя стадию создания гигантской строки в переменной.
Если после всех оптимизаций кода ошибка 400 или 413 (Payload Too Large) сохраняется, следует обратить внимание на настройки принимающей стороны. Посмотрим на основные параметры веб-серверов:
maxAllowedContentLength в файле web.config определяет максимальный размер запроса. По умолчанию он часто ограничен 30 МБ.client_max_body_size. Если ваш запрос проходит через прокси-сервер, убедитесь, что это значение больше размера вашего PDF-файла + 33% (накладные расходы Base64).HTTPСоединение обязательно увеличивайте время ожидания в конструкторе (параметр Таймаут). Для файлов объемом 10–20 МБ рекомендуется устанавливать таймаут не менее 60–120 секунд.Для успешной отправки больших файлов в формате Base64 через 1С мы рекомендуем:
+.ЗаписьXML и его метод ЗаписатьBase64() для автоматической потоковой конвертации данных.BOM, чтобы избежать ошибки 400.УстановитьИмяФайлаТела) или поток (УстановитьТелоИзПотока).Соблюдение этих правил позволит вам создавать надежные интеграции, способные обрабатывать файлы любого размера без потери данных и лишней нагрузки на сервер.