Быстрое чтение составных http сообщений multipart/form-data

26.09.21

Интеграция - WEB-интеграция

Алгоритм быстрого разбора составного http сообщения multipart/form-data.

Хочу поделиться алгоритмом по разбору http сообщений multipart/form-data, который позволяет обрабатывать данные сообщения на порядок быстрее аналогов. Пример аналога можно взять с ИТС (https://its.1c.ru/db/metod8dev/content/5917/hdoc). В данном примере интересует метод 

&НаСервере
Функция ПрочитатьСообщение(заголовки, тело)
        Разделитель = ПолучитьРазделительСоставногоСообщения(заголовки);
        Маркеры = Новый Массив();
        Маркеры.Добавить("==" + Разделитель);
        Маркеры.Добавить("==" + Разделитель + Символы.ПС);
        Маркеры.Добавить("==" + Разделитель + Символы.ВК);
        Маркеры.Добавить("==" + Разделитель + Символы.ВК + Символы.ПС);
        Маркеры.Добавить("==" + Разделитель + "==");               
        Текст = Неопределено;
        Изображение1 = Неопределено;
        Изображение2 = Неопределено;      
        ЧтениеДанных = Новый ЧтениеДанных(Тело);               
        // Переходим к началу первой части
        ЧтениеДанных.ПропуститьДо(Маркеры);
        // Далее в цикле читаем все части
        Пока Истина Цикл
               Часть = чтениеДанных.ПрочитатьДо(Маркеры);
               Если Не Часть.МаркерНайден Тогда
                       // Неправильно сформированное сообщение
                       Прервать;
               КонецЕсли;
               ЧтениеЧасти = Новый ЧтениеДанных(Часть.ОткрытьПотокДляЧтения());
               ЗаголовкиЧасти = ПрочитатьЗаголовки(ЧтениеЧасти);
               ИмяЧасти = ПолучитьИмяСообщения(ЗаголовкиЧасти);
               Если ИмяЧасти = "MessageText" Тогда
                       Текст = чтениеЧасти.ПрочитатьСимволы();
               ИначеЕсли ИмяЧасти = "image1" Тогда
                       Изображение1 = ЧтениеЧасти.Прочитать().ПолучитьДвоичныеДанные();
               ИначеЕсли ИмяЧасти = "image2" Тогда
                       Изображение2 = ЧтениеЧасти.Прочитать().ПолучитьДвоичныеДанные();
               КонецЕсли;                            
               Если Часть.ИндексМаркера = 4 Тогда
                       // Прочитали последнюю часть
                       Прервать;
               КонецЕсли;
        КонецЦикла;

        Возврат Новый Структура("Сообщение,Картинка1,Картинка2", 
                                         Текст, 
                                         Изображение1, 
                                         Изображение2); 
КонецФункции

Данный алгоритм, если кратко, строится на чтении потоков двоичных данных (более подробно можно в самой статье на ИТС). Данный вариант рабочий, но достаточно медленный, на обработку всего сообщения уходит чуть больше 10 секунд.

 

 

В алгоритме же, которым я хочу поделиться, все строится на:

  1. Вместо строковых маркеров используем помещение строк в буферы двоичных данных (реализовано таким образом потому что разделить буфер двоичных данных можно только с помощью других буферов);
  2. Выполнение чтения двоичных данных тела сообщения;
  3. Пропуска до первой части;
  4. Читаем двоичные данные в 1 общий буфер двоичных данных;
  5. Разделяем буфер с помощью маркеров и получаем массив буферов двоичных данных с нужными нам частями;
  6. Выполняем обход массива, при выполнении цикла открываем поток в оперативной памяти;
  7. Далее выполняем чтение потока в оперативной памяти;
  8. Закрываем чтение потока;
  9. Закрываем поток.

Сам алгоритм в коде выглядит следующим образом:

&НаСервере
Функция ПрочитатьСообщение(заголовки, тело)
	
	Разделитель = ПолучитьРазделительСоставногоСообщения(заголовки);
	
	Маркеры = Новый Массив();
	Маркеры.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("==" + Разделитель));
	Маркеры.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("==" + Разделитель + Символы.ПС));
	Маркеры.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("==" + Разделитель + Символы.ВК));
	Маркеры.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("==" + Разделитель + Символы.ВК + Символы.ПС));
	Маркеры.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("==" + Разделитель + "=="));
		
	текст = Неопределено;
	изображение1 = Неопределено;
	изображение2 = Неопределено;
		
	ЧтениеДанных = Новый ЧтениеДанных(тело);
		
	// Переходим к началу первой части
	ЧтениеДанных.ПропуститьДо(Маркеры);
	
	//Помещаем в общий буфер двоичных данных и разделяем буфер с помощью маркеров
	ОбщийБуферДвоичныхДанных = ЧтениеДанных.ПрочитатьВБуферДвоичныхДанных();
	БуферыДвоичныхДанных = ОбщийБуферДвоичныхДанных.Разделить(Маркеры);
	
	// Далее в цикле читаем все буферы
	Для Каждого Буфер Из БуферыДвоичныхДанных Цикл

		Поток = новый ПотокВПамяти(Буфер);
		ЧтениеЧасти = Новый ЧтениеДанных(Поток);
		ЗаголовкиЧасти = ПрочитатьЗаголовки(ЧтениеЧасти);
		ИмяЧасти = ПолучитьИмяСообщения(заголовкиЧасти);
		
		Если имяЧасти = "MessageText" Тогда
			текст = ЧтениеЧасти.Прочитать().ПолучитьДвоичныеДанные();;
		ИначеЕсли имяЧасти = "image1" Тогда
			изображение1 = ЧтениеЧасти.Прочитать().ПолучитьДвоичныеДанные();
		ИначеЕсли имяЧасти = "image2" Тогда
			изображение2 = ЧтениеЧасти.Прочитать().ПолучитьДвоичныеДанные();
		КонецЕсли;				
		
		ЧтениеЧасти.Закрыть();
		Поток.Закрыть();
		
	КонецЦикла;
	
	текст = ПолучитьСтрокуИзДвоичныхДанных(текст);
	
	Возврат Новый Структура("Сообщение,Картинка1,Картинка2", текст, изображение1, изображение2);
	
КонецФункции

Выполнение обработки всего сообщения с помощью данного алгоритма занимает всего сотые секунды:

 

 

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

Надеюсь, данный алгоритм сможет упростить работу с составными сообщениями http.

P.S. для работы алгоритма версия платформы должна быть не ниже 8.3.9.

http составное сообщение WEB multipart/form-data

См. также

Оптовая торговля Розничная торговля WEB-интеграция 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Платные (руб)

Онлайн-заказ - это решение для автоматизации процесса оформления заказов на сайте в торговых организациях. Продукт обеспечивает легкое взаимодействие между компанией и клиентами через веб-интерфейс, интегрированный с 1С:Предприятие. Система позволяет снизить операционные расходы, повысить лояльность клиентов и оптимизировать работу отдела продаж.

57600 руб.

26.11.2024    1235    1    1    

4

Сайты и интернет-магазины WEB-интеграция Системный администратор Программист Пользователь Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    18355    20    22    

18

Сайты и интернет-магазины Интеграция WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 Управленческий учет Платные (руб)

Интеграция 1С и Битрикс 24. Разработка имеет двухстороннюю синхронизацию 1С и Bitrix24 задачами. Решение позволяет создавать пользователя в 1С из Битрикс24 и наоборот. Данная разработка технически подходит под все основные конфигурации линейки продуктов 1С:Предприятие 8.3 (платформа начиная с 8.3.23): 1С:Управление торговлей, 1С:Управление Нашей фирмой 3, 1С:Комплексная автоматизация 2, Объединенное решение: Модуль 1С:CRM 3 (3.0.21.3) +1С:ERP Управление предприятием 2. При приобретении предоставляется 1 месяц бесплатных обновлений разработки. Доступна демо-версия продукта с подключением Вашего Битрикс24

7200 руб.

04.05.2021    20564    13    19    

18

WEB-интеграция Программист Бизнес-аналитик Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Оптовая торговля, дистрибуция, логистика ИТ-компания Платные (руб)

Модуль "Экспортер" — это расширение для 1С, предназначенное для автоматизации процессов выгрузки данных. Оно позволяет эффективно извлекать, преобразовывать и передавать данные из систем 1С в интеграционную платформу Spot2D. Подсистема упрощает настройку, снижает количество ручных операций и обеспечивает удобный контроль данных.

14400 руб.

20.12.2024    320    2    0    

5

WEB-интеграция Программист Руководитель проекта Платформа 1С v8.3 Конфигурации 1cv8 1С:Франчайзи, автоматизация бизнеса Платные (руб)

Расширение значительно упрощает написание API на 1С. Веб программисты получают простой и понятный доступ к 1С. Описание API создаётся автоматически и представляется в виде удобном как для человека, так и для программной обработки.

24000 руб.

27.09.2024    2483    1    0    

3
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. tormozit 7245 27.09.21 08:28 Сейчас в теме
Похоже на неоптимальную реализацию метода ЧтениеДвоичныхДанных.ПрочитатьДо() в платформе. Думаю имеет смысл указать версию платформы, на которой были сделаны замеры.
2. user1464690 27.09.21 11:19 Сейчас в теме
(1) Проблема не только в методе ЧтениеДвоичныхДанных.ПрочитатьДо(), но еще наблюдается и с ЧтениеДвоичныхДанных.Разделить() (т.е если предварительно разделить чтение данных по маркерам на части и дальше выполнять обход по массиву частей), по времени выполняется столько же как и в примере с ИТС. Замеры делались на версии платформы 8.3.17, на версиях ниже аналогичная картина.
Akcium; Поручик; +2 Ответить
3. portal80 09.11.21 09:45 Сейчас в теме
Просто -напросто бестолковый пример в ИТС выкинуть и уволить написавшего.

Есть корректные решения по чтению составных сообщений?

Или каждый раз самому писать костыли ?
4. bayselonarrend 2297 08.12.22 13:37 Сейчас в теме
Спасибо! Очень хороший метод. Пользовался примером с ИТС до него. Для разбора POST из нескольких текстовых полей и трех файлов, (~10 мб каждый) примеру с ИТС требовалось примерно минута, а этот отрабатывает за 2 секунды всего.
Оставьте свое сообщение