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

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

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

В наличии

Алгоритм быстрого разбора составного 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.

has been added to your cart:
Оформление заказа