Книга: Технологии интеграции "1С:Предприятия 8.3""
Назад: Создание сервиса для формирования составного сообщения
Дальше: XDTO-сериализация
Разбор составного сообщения на стороне клиента

Теперь посмотрим, как мы можем работать с составными сообщениями на стороне клиента. Нам необходимо получить ответ HTTP-сервиса, распаковать вложенные в ответ сообщения и показать их содержимое.

В форму нашей демонстрационной обработки добавим реквизиты типа Строка:

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

Также добавим в форму команду ОтправитьHTTPЗапрос. Из обработчика этой команды мы вызываем серверную процедуру Выполнить_HTTPЗапрос(), в которой и происходят получение, разбор и отображение ответа HTTP-сервиса (листинг 6.111).

Листинг 6.111. Процедура «Выполнить_HTTPЗапрос()»

&НаСервере

Процедура Выполнить_HTTPЗапрос()

 

HTTPСоединение = Новый HTTPСоединение("localhost");

 

// Сформировать запрос, отправить на сервер и получить ответ.

Запрос = Новый HTTPЗапрос("Web_1C/hs/multipart");

Ответ = HTTPСоединение.Получить(Запрос);

 

// Разобрать ответ на составные части.

// Результат представляет собой структуру, содержающую текст и картинки из составного HTTP-сообщения.

Результат = ПрочитатьСообщение(Ответ.Заголовки, Ответ.ПолучитьТелоКакДвоичныеДанные());

HTTPСообщение = Результат.Сообщение;

 

// Создать объекты Картинка из двоичных данных изображений, полученных с сервера.

Картинка1 = Новый Картинка(Результат.Картинка1);

Картинка2 = Новый Картинка(Результат.Картинка2);

 

// Поместить полученные картинки во временное хранилище.

АдресКартинки1 = ПоместитьВоВременноеХранилище(Картинка1);

АдресКартинки2 = ПоместитьВоВременноеХранилище(Картинка2);

 

КонецПроцедуры

Отправка запросов и получение ответов от HTTP-сервисов подробно рассматривались в первой главе в разделе «». Поэтому в данном примере мы не будем еще раз на этом останавливаться. Поясним только моменты, касающиеся работы с двоичными данными.

После отправки запроса к нашему HTTP-сервису, определенному ранее, мы вызываем функцию ПрочитатьСообщение() и передаем туда заголовки и тело ответа, полученное методом ПолучитьТелоКакДвоичныеДанные(). В этой функции и выполняется разбор полученного от сервиса составного сообщения (листинг 6.112).

Листинг 6.112. Функция «ПрочитатьСообщение()»

&НаСервереБезКонтекста

Функция ПрочитатьСообщение(Заголовки, Тело)

 

Разделитель = ПолучитьРазделительСоставногоСообщения(Заголовки);

 

Маркеры = Новый Массив();

Маркеры.Добавить("==" + Разделитель);

Маркеры.Добавить("==" + Разделитель + Символы.ПС);

маркеры.Добавить("==" + Разделитель + Символы.ВК);

Маркеры.Добавить("==" + Разделитель + Символы.ВК + Символы.ПС);

Маркеры.Добавить("==" + Разделитель + "==");

 

Текст = Неопределено;

Изображение1 = Неопределено;

Изображение2 = Неопределено;

 

ЧтениеДанных = Новый ЧтениеДанных(Тело);

 

// Перейти к началу первой части.

ЧтениеДанных.ПропуститьДо(маркеры);

 

// Прочитать в цикле все части тела сообщения.

Пока Истина Цикл

Часть = чтениеДанных.ПрочитатьДо(Маркеры);

 

Если Не Часть.МаркерНайден Тогда

// Неправильно сформированное сообщение

Прервать;

КонецЕсли;

 

ЧтениеЧасти = Новый ЧтениеДанных(Часть.ОткрытьПотокДляЧтения());

ЗаголовкиЧасти = ПрочитатьЗаголовки(ЧтениеЧасти);

ИмяЧасти = ПолучитьИмяСообщения(ЗаголовкиЧасти);

 

Если ИмяЧасти = "MessageText" Тогда

Текст = ЧтениеЧасти.ПрочитатьСимволы();

ИначеЕсли имяЧасти = "image1" Тогда

Изображение1 = ЧтениеЧасти.Прочитать().ПолучитьДвоичныеДанные();

ИначеЕсли имяЧасти = "image2" Тогда

Изображение2 = ЧтениеЧасти.Прочитать().ПолучитьДвоичныеДанные();

КонецЕсли;

 

Если Часть.ИндексМаркера = 4 Тогда

// Прочитана последняя часть

Прервать;

КонецЕсли;

КонецЦикла;

 

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

 

КонецФункции

В этой функции мы сначала получаем разделитель составного сообщения из заголовков сообщения с помощью функции ПолучитьРазделительСоставногоСообщения(), приведенной в листинге 6.113.

Затем формируем массив маркеров, описывающих все возможные маркеры, разделяющие составное сообщение на части.

После этого создаем объект ЧтениеДанных на основе тела ответа, переданного в функцию в виде двоичных данных, и методом ПропуститьДо() позиционируемся на чтении первой части сообщения. В цикле методом ПрочитатьДо() объекта ЧтениеДанных мы читаем сообщение по частям вплоть до последнего маркера.

Для каждой прочитанной части мы получаем заголовки этой части сообщения в виде объекта Соответствие с помощью функции ПрочитатьЗаголовки(), приведенной в листинге 6.114. А также получаем имя вложенного сообщения из заголовков этой части сообщения с помощью функции ПолучитьИмяСообщения(), приведенной в листинге 6.115.

Затем в зависимости от имени прочитанной части получаем либо текст, либо двоичные данные картинок. И после окончания чтения всех частей сообщения упаковываем эти значения в структуру, которую функция возвращает в процедуру Выполнить_HTTPЗапрос() – см. листинг 6.111. После чего в этой процедуре текст и картинки распаковываются и отображаются в соответствующих элементах формы обработки.

Вспомогательную функцию ПолучитьРазделительСоставногоСообщения() заполним следующим образом (листинг 6.113).

Листинг 6.113. Функция «СоздатьСообщение_Изображение()»

&НаСервереБезКонтекста

Функция ПолучитьРазделительСоставногоСообщения(Заголовки)

 

ТипСодержимого = Заголовки.Получить("Content-Type");

 

Свойства = СтрРазделить(ТипСодержимого, ";", Ложь);

Граница = Неопределено;

 

Для Каждого Свойство Из Свойства Цикл

Части = СтрРазделить(Свойство, "=", Ложь);

ИмяСвойства = СокрЛП(Части[0]);

 

Если ИмяСвойства <> "boundary" Тогда

Продолжить;

КонецЕсли;

 

Граница = СокрЛП(Части[1]);

Прервать;

КонецЦикла;

 

Возврат Граница;

 

КонецФункции

При поиске строки-разделителя составного сообщения из заголовков предполагается, что значение разделителя задается в заголовке Content-Type в виде Content-Type: multipart/form-data; boundary<=Разделитель>.

Для разбора строк во всех вспомогательных функциях используется функция глобального контекста СтрРазделить().

Вспомогательную функцию ПрочитатьЗаголовки() заполним следующим образом (листинг 6.114).

Листинг 6.114. Функция «ПрочитатьЗаголовки()»

&НаСервереБезКонтекста

Функция ПрочитатьЗаголовки(Чтение)

 

Заголовки = Новый Соответствие();

 

Пока Истина Цикл

Строка = Чтение.ПрочитатьСтроку();

Если Строка = "" Тогда

Прервать;

КонецЕсли;

 

Части = СтрРазделить(Строка, ":");

ИмяЗаголовка = СокрЛП(Части[0]);

Значение = СокрЛП(Части[1]);

 

Заголовки.Вставить(ИмяЗаголовка, Значение);

КонецЦикла;

 

Возврат Заголовки;

 

КонецФункции

Вспомогательную функцию ПолучитьИмяСообщения() заполним следующим образом (листинг 6.115).

Листинг 6.115. Функция «ПолучитьИмяСообщения(

&НаСервереБезКонтекста

Функция ПолучитьИмяСообщения(Заголовки)

 

Описание = Заголовки.Получить("Content-Disposition");

 

Свойства = СтрРазделить(Описание, ";", Ложь);

Имя = Неопределено;

 

Для Каждого Свойство Из Свойства Цикл

Части = СтрРазделить(Свойство, "=", Ложь);

ИмяСвойства = СокрЛП(Части[0]);

 

Если ИмяСвойства <> "name" Тогда

Продолжить;

КонецЕсли;

 

Имя = СокрЛП(Части[1]);

Прервать;

КонецЦикла;

 

Возврат Имя;

 

КонецФункции

В этой функции имя сообщения получается из заголовка Content-Disposition в виде Content-Disposition: form-data; name<=Имя сообщения>.

Назад: Создание сервиса для формирования составного сообщения
Дальше: XDTO-сериализация