Передача файлов через API — одна из самых распространенных задач при интеграции 1С со сторонними сервисами. Однако формат multipart/form-data имеет множество скрытых нюансов, из-за которых сервер может возвращать ошибки вроде «Файл не найден» или «Некорректный формат данных», даже если визуально тело запроса выглядит правильно. Разберем по шагам, как сформировать корректный запрос, избежать проблем с кодировками и использовать современные возможности платформы 1С.
Рассмотрим стандартную ситуацию: у нас есть рабочий пример на cURL, но при попытке реализовать его в 1С сервер выдает ошибку. Основные причины обычно скрываются в трех аспектах:
Символы.ПС вместо стандартного для протокола HTTP CRLF (Символы.ВК + Символы.ПС).Если ваша версия платформы позволяет, рекомендуем отказаться от ручного формирования текстовых файлов и строк. Начиная с версии 8.3.18, в 1С появился объект РазделениеДанныхВФорматеMultipartFormData, который берет на себя всю работу по расстановке границ (boundary) и формированию заголовков частей.
Проанализируем пример использования этого объекта:
// Создаем объект для формирования тела запроса
Разделитель = Новый РазделениеДанныхВФорматеMultipartFormData();
// Создаем часть с файлом
ЧастьФайла = Новый ЧастьДанныхВФорматеMultipartFormData();
ЧастьФайла.Заголовки.Вставить("Content-Disposition", "form-data; name=""file""; filename=""report.xlsx""");
ЧастьФайла.Заголовки.Вставить("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
// Устанавливаем тело из двоичных данных файла
ДвоичныеДанныеФайла = Новый ДвоичныеДанные("D:/report.xlsx");
ЧастьФайла.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеФайла);
// Добавляем часть в общий поток
Разделитель.ДобавитьЧасть(ЧастьФайла);
// Получаем boundary и тело для запроса
Boundary = Разделитель.Граница;
ТелоЗапроса = Разделитель.ПолучитьТелоКакПоток();
// Формируем запрос
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
Запрос = Новый HTTPЗапрос("/api/v1/upload", Заголовки);
Запрос.УстановитьТелоИзПотока(ТелоЗапроса);
// Отправляем
Соединение = Новый HTTPСоединение("api.service.ru",,,, , , Новый ЗащищенноеСоединениеOpenSSL());
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Этот метод является наиболее надежным, так как платформа автоматически соблюдает стандарты RFC, включая правильные переносы строк и структуру границ.
Если вы работаете на более старых версиях платформы, нам придется собрать тело запроса «вручную». Рассмотрим наиболее стабильный вариант — через объединение файлов. Это позволяет избежать проблем с памятью при передаче больших файлов и дает полный контроль над байтами.
Важный нюанс: Одной из главных причин ошибок является кодировка. При записи текста через ЗаписьТекста по умолчанию 1С добавляет BOM (специальные символы в начале файла). Многие веб-серверы (особенно на PHP/Python) не ожидают их увидеть в multipart и выдают ошибку. Чтобы этого избежать, при создании ЗаписьТекста необходимо явно указывать параметр ИспользоватьBOM как Ложь.
Разберем реализацию по шагам:
// 1. Подготовка переменных
Boundary = СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", "");
ИмяФайлаНачало = ПолучитьИмяВременногоФайла("txt");
ИмяФайлаКонец = ПолучитьИмяВременногоФайла("txt");
ПутьКФайлуЭксель = "D:/11111111_ACC.xlsx";
// 2. Формируем заголовочную часть
// Указываем КодировкаТекста.UTF8 и ПЯТЫЙ параметр Ложь (отключение BOM)
ЗаписьТекста = Новый ЗаписьТекста(ИмяФайлаНачало, КодировкаТекста.UTF8, Символы.ВК + Символы.ПС, Ложь, Ложь);
ЗаписьТекста.ЗаписатьСтроку("--" + Boundary);
// Важно: имя поля и имя файла должны быть в кавычках
ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""data.xlsx""");
// Для .xlsx используем корректный MIME-тип
ЗаписьТекста.ЗаписатьСтроку("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
ЗаписьТекста.ЗаписатьСтроку(""); // Обязательная пустая строка перед двоичными данными
ЗаписьТекста.Закрыть();
// 3. Формируем завершающую часть
ЗаписьТекста = Новый ЗаписьТекста(ИмяФайлаКонец, КодировкаТекста.UTF8, Символы.ВК + Символы.ПС, Ложь, Ложь);
ЗаписьТекста.ЗаписатьСтроку(""); // Перенос после двоичных данных
ЗаписьТекста.ЗаписатьСтроку("--" + Boundary + "--");
ЗаписьТекста.Закрыть();
// 4. Объединяем файлы в один финальный файл тела
ИмяФайлаТела = ПолучитьИмяВременногоФайла("post");
МассивФайлов = Новый Массив;
МассивФайлов.Добавить(ИмяФайлаНачало);
МассивФайлов.Добавить(ПутьКФайлуЭксель);
МассивФайлов.Добавить(ИмяФайлаКонец);
ОбъединитьФайлы(МассивФайлов, ИмяФайлаТела);
// 5. Отправка запроса
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
Запрос = Новый HTTPЗапрос("/api/endpoint", Заголовки);
Запрос.УстановитьИмяФайлаТела(ИмяФайлаТела);
// Результат
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Проанализируем еще несколько важных моментов, которые помогут, если решение выше все равно не проходит проверку на стороне сервера:
.xlsx стандартом является application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, некоторые старые или специфические API могут требовать application/octet-stream или даже устаревший application/vnd.ms-excel. Попробуйте сменить тип, если сервер жалуется на формат.filename старайтесь передавать только имя файла с расширением (например, "data.xlsx"), а не полный путь ("D:/files/data.xlsx"). Некоторые системы безопасности на стороне сервера блокируют запросы, содержащие абсолютные пути.\r\n. В 1С это сочетание Символы.ВК + Символы.ПС. При использовании ЗаписьТекста передавайте это сочетание в третий параметр конструктора.webhook.site. Отправьте запрос из 1С туда и сравните полученный результат с рабочим запросом из Postman или cURL. Особое внимание уделите наличию лишних пробелов или невидимых символов в самом начале тела запроса.Резюме: Основной секрет успеха при отправке .xlsx через 1С — это чистота бинарных данных. Использование ОбъединитьФайлы гарантирует, что сам файл Excel не будет поврежден при преобразовании в строку, а отключение BOM при записи текстовых заголовков сделает ваше сообщение понятным для любого веб-сервера.