Как правильно настроить POST-запрос multipart/form-data в 1С для работы с внешними API (на примере OCR.space)?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Часто разработчики 1С сталкиваются с ситуацией, когда запрос, идеально работающий в Postman или через curl, выдает ошибку при попытке реализовать его в коде 1С. Особенно это касается передачи изображений или файлов через формат multipart/form-data. В данной статье мы разберем, почему возникают ошибки распознавания расширения файла, как правильно формировать тело запроса и почему стоит отказаться от использования COM-объекта WinHttp.WinHttpRequest.5.1 в пользу встроенных средств платформы.

Анализируем причину ошибки: почему API не видит данные?

Разберем типичную ситуацию: автор пытается отправить изображение в формате base64 для распознавания текста. API возвращает ошибку, утверждая, что не может распознать расширение или файл пуст. Основная причина здесь кроется не в логике API, а в физической структуре HTTP-пакета, который формирует 1С.

Проанализируем ключевые факторы, влияющие на успех запроса:

  1. Символы переноса строк (CRLF): В стандарте HTTP разделители между частями multipart данных должны состоять из последовательности "Возврат каретки" и "Перевод строки" (\r\n). В 1С при использовании многострочной строки через вертикальную черту | используется только символ ПС (\n). Большинство серверов (включая OCR.space) не смогут корректно распарсить границы (boundary), если они разделены не по стандарту.
  2. Формат Base64: Для передачи изображения через параметр base64Image недостаточно просто получить строку. API часто ожидает Data URI заголовок, например: data:image/jpeg;base64,.... Без него сервер может не понять тип передаваемого контента.
  3. Кодировка и бинарные данные: При передаче текста через WinHttp происходит неявная конвертация в Unicode или ANSI. Если в теле запроса присутствуют бинарные части, они могут быть повреждены.

Шаг 1. Формирование корректного тела запроса

Рассмотрим, как правильно собрать тело запроса multipart/form-data. Нам необходимо явно использовать Символы.ВК + Символы.ПС для каждого переноса строки. Выясним, как должна выглядеть структура одной части запроса.


Разделитель = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
ВКПС = Символы.ВК + Символы.ПС;

ТелоЗапроса = "--" + Разделитель + ВКПС;
ТелоЗапроса = ТелоЗапроса + "Content-Disposition: form-data; name=""base64Image""" + ВКПС + ВКПС;
ТелоЗапроса = ТелоЗапроса + "data:image/jpeg;base64," + СтрокаBase64 + ВКПС;

ТелоЗапроса = ТелоЗапроса + "--" + Разделитель + ВКПС;
ТелоЗапроса = ТелоЗапроса + "Content-Disposition: form-data; name=""language""" + ВКПС + ВКПС;
ТелоЗапроса = ТелоЗапроса + "eng" + ВКПС;

ТелоЗапроса = ТелоЗапроса + "--" + Разделитель + "--" + ВКПС;

Важный нюанс: Обратите внимание на финальный разделитель. Он должен заканчиваться двумя дефисами: --Разделитель--. Это сигнализирует серверу об окончании передачи данных.

Шаг 2. Отказ от COM-объекта в пользу HTTPСоединение

Использование WinHttp.WinHttpRequest.5.1 в современной 1С является избыточным и потенциально опасным. Рассмотрим преимущества использования встроенных объектов HTTPСоединение и HTTPЗапрос. Они позволяют корректно работать с кодировками и автоматически устанавливать важные заголовки, такие как Content-Length.

Проанализируем пример кода, который реализует отправку данных через встроенные механизмы:


// Настройка соединения
Сервер = "api.ocr.space";
Соединение = Новый HTTPСоединение(Сервер, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());

// Формирование заголовков
ЗаголовокHTTP = Новый Соответствие;
ЗаголовокHTTP.Вставить("apikey", "ВашКлючAPI");
// Важно: boundary в заголовке должен совпадать с тем, что в теле
ЗаголовокHTTP.Вставить("Content-Type", "multipart/form-data; boundary=" + Разделитель);

// Создание запроса
Запрос = Новый HTTPЗапрос("/parse/image", ЗаголовокHTTP);

// Преобразование строки тела в двоичные данные (UTF-8 без BOM)
ДанныеТела = ПолучитьДвоичныеДанныеИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8, Ложь);
Запрос.УстановитьТелоИзДвоичныхДанных(ДанныеТела);

// Отправка и получение ответа
Ответ = Соединение.ОтправитьДляОбъекта(Запрос);
ТекстОтвета = Ответ.ПолучитьТелоКакСтроку();

Шаг 3. Работа с бинарными потоками (продвинутый уровень)

Если изображение очень большое, формирование огромной строки в памяти может привести к ошибке Недостаточно памяти. Разберем, как использовать ПотокВПамяти и ЗаписьДанных для более эффективной работы. Этот метод позволяет записывать данные в поток порциями.


Поток = Новый ПотокВПамяти();
ЗаписьДанных = Новый ЗаписьДанных(Поток, КодировкаТекста.UTF8);

ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""language""");
ЗаписьДанных.ЗаписатьСтроку(""); // Пустая строка между заголовком и данными
ЗаписьДанных.ЗаписатьСтроку("eng");

// Повторяем для всех полей...

ЗаписьДанных.Закрыть();
РезультатБинарный = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Запрос.УстановитьТелоИзДвоичныхДанных(РезультатБинарный);

Использование ЗаписьДанных с параметром кодировки гарантирует, что все символы будут корректно преобразованы в UTF-8, а переходы строк будут соответствовать стандарту.

Типичные ошибки, которые стоит проверить

Если запрос все равно возвращает ошибку, проанализируем следующие моменты:

Заключение

Мы выяснили, что ключ к успешному POST-запросу из 1С к внешним сервисам — это строгое соблюдение структуры протокола HTTP и использование современных инструментов платформы. Отказ от COMОбъект в пользу HTTPЗапрос не только делает код более читаемым и кроссплатформенным (работает в Linux-версиях сервера 1С), но и избавляет от проблем с кодировками и расчетом длины контента.

← На главную