Каталог решений - Сервис управления списком баз wcib (WebCommonInfoBases) посредством JSON

Сервис управления списком баз wcib (WebCommonInfoBases) посредством JSON

Сервис управления списком баз wcib (WebCommonInfoBases) посредством JSON

В наличии

Пример реализации http-сервиса управления списками баз без использования SOAP

Категория:

Описание

Предыстория:

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

4 запроса:

Лаунчер 1cestart для варианта JSON посылает 4 запроса:

1- HEAD запрос на эндпоинт "WebCommonInfoBases". Название зашито в лаунчере, он добавляет его сам к указанному в настройках URl. На этот запрос необходимо отправить ответ с кодом 200, только в таком случае мы получим ожидаемый запрос на проверку обновления списка в нужном формате. В противном случае мы получим SOAP запрос.
2- GET запрос на эндпоинт "WebCommonInfoBases". Тут мы должны указать необходимость обновления списка баз и адрес сервиса, возвращающего этот список в формате v8i:

Пример тела ответа:

{
  "root":
  {
    "InfoBasesChanged": true,
    "URL": "http:\\СервисПолученияСписка_v8i"
  }
}

 

3- HEAD запрос на указанный ранее сервис. Принцип все тот же, отвечаем с кодом 200

4- GET запрос на указанный ранее сервис. Возвращаем тело в формате JSON

 

Пример тела ответа:

{
  "root":
  {
    "ClientID": "none",
    "InfoBasesCheckCode": "none",
    "InfoBases":"Описание в формате v8i"
  }
}

 

Настройка лаунчера

В настройках диалога запуска необходимо прописать путь к публикации первого эндпоинта по которому будет происходить проверка необходимости обновления и получение URL второго эндпоинта

 

Реализация

Создаем 2 эндпоинта:

Корневой URL у первого эндпоинта должен быть именно таким: "WebCommonInfoBases"

  

Пример тела модуля первого эндпоинта:


#Область ПрограммныйИнтерфейс

Функция CheckInfoBases_GET(Запрос)
	
	Попытка
	
		ClientID 					= Строка(Запрос.ПараметрыЗапроса["ClientID"]);
		
		// Может быть пустым
		InfoBasesCheckCode			= Строка(Запрос.ПараметрыЗапроса["InfoBasesCheckCode"]);
		
		// Может передать веб-сервер
		ЛогинПользователя			= Запрос.ПараметрыЗапроса.Получить("UserID");
		
		ИдентификаторПользователя 	= Запрос.ПараметрыURL.Получить("user_guid");
		
		Если ПустаяСтрока(ClientID) Тогда
			Ответ = Новый HTTPСервисОтвет(404);
			Возврат Ответ;
		КонецЕсли;
		
		Если Не ЗначениеЗаполнено(ИдентификаторПользователя) 
			И Не ЗначениеЗаполнено(ЛогинПользователя) Тогда
			
			Ответ = Новый HTTPСервисОтвет(404);
			Возврат Ответ;
			
		КонецЕсли;	
		
		InfoBasesChanged = Ложь;
		URL = "";
		
		СтруктураОтвета = CheckInfoBases(ClientID, InfoBasesCheckCode, InfoBasesChanged, URL
										, Запрос.БазовыйURL, ЛогинПользователя, ИдентификаторПользователя);
		
		Тело = СтроковыеФункцииКлиентСервер.КонвертироватьВJson(СтруктураОтвета);
		Ответ = Новый HTTPСервисОтвет(200);
		Ответ.УстановитьТелоИзСтроки(Тело);
		
		Ответ.Заголовки["Content-Type"]  = "application/json;charset=utf-8";
		Ответ.Заголовки["Cache-Control"] = "no-cache";
		
		Возврат Ответ;
		
	Исключение
		
		ЗаписьЖурналаРегистрации("CheckInfoBases.JSON", УровеньЖурналаРегистрации.Ошибка,
								,,СлужебныйКлиентСервер.ПодробныйТекстОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение;
		
	КонецПопытки
		
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедуры

Функция ПустойИдентификатор()
	Возврат "00000000-0000-0000-0000-000000000000";
КонецФункции

Функция CheckInfoBases(ClientID, InfoBaseCheckCode, InfoBasesChanged, URL, БазовыйURL, ЛогинПользователя, ИдентификаторПользователя)
	
    InfoBasesChanged = Ложь;	
	
	// TODO: Тип доступа опряделяет список для пользователя (для типа web и rdp разные списки)
	// Должен определяться по эндпоинту. Нужны разные эндпоинты для разных типов доступа
	ТипДоступа = "rdp";
	
	УстановитьПривилегированныйРежим(Истина);
	
	АдресЗащищенногоВС = Константы.URLПолученияСпискаБаз.Получить();
	
	Если ЗначениеЗаполнено(ИдентификаторПользователя) Тогда
		АдресЗащищенногоВС = АдресЗащищенногоВС + ИдентификаторПользователя+"/";	
	КонецЕсли;
	
	Если ClientID = ПустойИдентификатор()
		И InfoBaseCheckCode = ПустойИдентификатор() Тогда
		// это первое обращение клиента
		InfoBasesChanged = Истина;
		URL = АдресЗащищенногоВС;
		СтруктураОтвета = СтруктурыДанныхСервер.СтруктураОтветаПроверкаОбновления(InfoBasesChanged, URL);
		
	КонецЕсли;
	
	СтруктураОтвета = ФункцииУправленияСервер.ПроверитьПотребностьОбновления(ЛогинПользователя, ИдентификаторПользователя
																			, InfoBaseCheckCode, ТипДоступа); 
	
	Возврат СтруктураОтвета;	
	
КонецФункции

Функция RootHEAD(Запрос)
	Ответ = Новый HTTPСервисОтвет(200);
	//Ответ.Заголовки["Content-Type"]	 = "application/json;charset=utf-8";
	//Ответ.Заголовки["Cache-Control"] = "no-cache";
	Возврат Ответ;
КонецФункции

#КонецОбласти

 

Пример тела модуля второго эндпоинта:



Функция GetInfoBasesGetInfoBases_GET(Запрос)
	
	// Пропускаем запросы HEAD
	// Заглушка, необходимая 1С стартеру для отправки JSON
	Если Запрос.HTTPМетод = "" Тогда
		
		Ответ = Новый HTTPСервисОтвет(200);
		// Работает даже без заголовков
		//Ответ.Заголовки["Content-Type"]	 = "application/json;charset=utf-8";
		//Ответ.Заголовки["Cache-Control"] = "no-cache";
		Возврат Ответ;
		
	ИначеЕсли Запрос.HTTPМетод = "GET" Тогда
		
		Попытка
			
			ClientID 			= Запрос.ПараметрыЗапроса["ClientID"];
			InfoBasesCheckCode	= Запрос.ПараметрыЗапроса["InfoBasesCheckCode"];
			
			// Может передать веб-сервер
			ЛогинПользователя	= Запрос.ПараметрыЗапроса.Получить("UserID");
			
			ИдентификаторПользователя 	= Запрос.ПараметрыURL.Получить("user_guid");
			
			InfoBases 			= "";
			
			GetInfoBases(ClientID, InfoBasesCheckCode, InfoBases, Запрос.БазовыйURL, ЛогинПользователя, ИдентификаторПользователя);
			
			ДанныеОтвета = Новый Структура("root", Новый Структура("ClientID,InfoBasesCheckCode,InfoBases"
																	, ClientID, InfoBasesCheckCode, InfoBases));
			
			Тело = СтроковыеФункцииКлиентСервер.КонвертироватьВJson(ДанныеОтвета);
			
			Ответ = Новый HTTPСервисОтвет(200);
			Ответ.УстановитьТелоИзСтроки(Тело);
			
			Ответ.Заголовки["Content-Type"]	 = "application/json;charset=utf-8";
			Ответ.Заголовки["Cache-Control"] = "no-cache";
			
			Возврат Ответ;
			
		Исключение
			
			ЗаписьЖурналаРегистрации("GetInfoBases.JSON", УровеньЖурналаРегистрации.Ошибка,,
									,СлужебныйКлиентСервер.ПодробныйТекстОшибки(ИнформацияОбОшибке()));
			ВызватьИсключение;
			
		КонецПопытки
		
	Иначе
		
		Ответ = Новый HTTPСервисОтвет(405);	
		Возврат Ответ;
		
	КонецЕсли;
	
КонецФункции



#Область СлужебныеПроцедуры

Процедура GetInfoBases(ClientID, InfoBaseCheckCode, InfoBases, БазовыйURL, ЛогинПользователя, ИдентификаторПользователя)
	
	УстановитьПривилегированныйРежим(ИСТИНА);
		
	ТипДоступа = "rdp";
	
	ВспомогательныеФункцииСервер.ИнициализироватьВнешнийИсточник(Константы.АдресСервера.Получить());
	
	Если ЛогинПользователя <> Неопределено Тогда 
		РезультатJSON = ВнешниеИсточникиДанных.wcib_db.public_get_v8i_list_uid(ЛогинПользователя, ТипДоступа);
	Иначе
		РезультатJSON = ВнешниеИсточникиДанных.wcib_db.public_get_v8i_list_guid(ИдентификаторПользователя, ТипДоступа);
	КонецЕсли;
	
	СтруктураОтвета = СтроковыеФункцииКлиентСервер.КонвертироватьJsonВСтруктуру(РезультатJSON);
	
	InfoBaseCheckCode = СтруктураОтвета.version;
	
	Если ClientID = ПустойИдентификатор() Тогда
		ClientID = Строка(Новый УникальныйИдентификатор());
	КонецЕсли;
	
	InfoBases = ПолучитьСписокИБ(СтруктураОтвета.infobases);
	
КонецПроцедуры

Функция ПолучитьСписокИБ(ДанныеСписка) Экспорт
	
	Если ДанныеСписка = Неопределено Тогда
		ДанныеСписка = Новый Массив;	
	КонецЕсли;
	
	ЧислоИБ = ДанныеСписка.Количество(); 
	
	УстановитьПривилегированныйРежим(Истина); 
		
	//собираем в дерево
	
	//соответствие(Группа): массив(Список ИБ): структура(Элемент ИБ)

	Результат = "";	

	ИспользоватьФайл = ЧислоИБ > 1000;
	
	Если ИспользоватьФайл Тогда
		ИмяВременногоФайла = ПолучитьИмяВременногоФайла("v8i");
		ЗТ = Новый ЗаписьТекста(ИмяВременногоФайла, КодировкаТекста.UTF8);
	КонецЕсли;
	
	Для Каждого JSONСтруктураБазы Из ДанныеСписка Цикл
		
		JSONСтруктураБазы = СтрЗаменить(JSONСтруктураБазы, "\", "\\");
		
		СтруктураБазы = СтроковыеФункцииКлиентСервер.КонвертироватьJsonВСтруктуру(JSONСтруктураБазы);
		
		Группа = Новый Массив();
	
		ОписаниеИБ = Новый Структура("Наименование,Строки", СтруктураБазы.name, Новый Массив());
		СтрокиИБ = ОписаниеИБ.Строки;
	
		ConnectString = ВспомогательныеФункцииСервер.СформироватьСтрокуПодключения(СтруктураБазы);
	
		СтрокиИБ.Добавить(ConnectString);
		СтрокиИБ.Добавить("ID=" + СтруктураБазы.base_id);
		 
		СтрокиИБ.Добавить("OrderInList=" + СтруктураБазы.order_in_list);
		
		Если СтруктураБазы.app_arch <> Неопределено Тогда
			СтрокиИБ.Добавить("AppArch=" + СтруктураБазы.app_arch);
		КонецЕсли;
		
		СтрокаДополнительныхПараметров = "";
		
		Если СтруктураБазы.use_ib_autorization = Истина Тогда
			
			ИмяПользователя = СтруктураБазы.iblogin;
			Пароль = ?(ЗначениеЗаполнено(СтруктураБазы.ibpwd), СтруктураБазы.ibpwd, "");
			
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "/N " + ИмяПользователя + " ";
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "/P " + Пароль + " "; 
						
		КонецЕсли;
		
		// Авторизация на веб-сервере (для получения списка баз)
		Если  СтруктураБазы.wslogin <> Неопределено Тогда
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "/WSN " + СтруктураБазы.wslogin + " ";
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "/WSP " + СтруктураБазы.wspwd + " ";
		КонецЕсли;
		
		// Если используется прокси для WS
		Если СтруктураБазы.use_proxy = 2 Тогда
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "/Proxy ";
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "-PSrv " + СтруктураБазы.psrv + " ";
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "-PPort " + Формат(СтруктураБазы.pport, "ЧГ=") + " ";
			Если СтруктураБазы.puser <> Неопределено Тогда
				СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "-PUser " + СтруктураБазы.puser + " ";	
			КонецЕсли;
			Если СтруктураБазы.ppwd <> Неопределено Тогда
				СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "-PPwd " + СтруктураБазы.ppwd + " ";	
			КонецЕсли;
		КонецЕсли;
		
		Если СтруктураБазы.technical_specialist_mode = Истина Тогда
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "/TechnicalSpecialistMode ";	
		КонецЕсли;
		
		Если СтруктураБазы.main_window_mode <> Неопределено Тогда
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "/MainWindowMode " + СтруктураБазы.main_window_mode + " ";	
		КонецЕсли;
		
		Если СтруктураБазы.clear_cache = Истина Тогда
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "/ClearCache ";	
		КонецЕсли;

		Если СтруктураБазы.update_ib = Истина Тогда
			СтрокаДополнительныхПараметров = СтрокаДополнительныхПараметров + "/C ЗапуститьОбновлениеИнформационнойБазы";
		КонецЕсли;
		
		Если Не ПустаяСтрока(СтрокаДополнительныхПараметров) Тогда
			СтрокиИБ.Добавить("AdditionalParameters=" + СтрокаДополнительныхПараметров);
		КонецЕсли;
		
		Группа.Добавить(ОписаниеИБ);
	
		//рендерим дерево в v8i
		//если дерево больше 1000, используем файл как буфер, потому что конкатенация длинных строк в платформе работает медленно
	
		Для Каждого ОписаниеИБ из Группа Цикл
			Если ИспользоватьФайл Тогда
				ЗТ.ЗаписатьСтроку("[" + ОписаниеИБ.Наименование + "]");
			Иначе
				Результат = Результат + "[" + ОписаниеИБ.Наименование + "]" + Символы.ПС;
			КонецЕсли;
			Для Каждого СтрокаИБ из ОписаниеИБ.Строки Цикл
				Если ИспользоватьФайл Тогда
					ЗТ.ЗаписатьСтроку(СтрокаИБ);
				Иначе
					Результат = Результат + СтрокаИБ + Символы.ПС;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	Если ИспользоватьФайл Тогда
		ЗТ.Закрыть();
		ЧТ = новый ЧтениеТекста(ИмяВременногоФайла, КодировкаТекста.UTF8);
		Результат = ЧТ.Прочитать();
		ЧТ.Закрыть();
		УдалитьФайлы(ИмяВременногоФайла);
	КонецЕсли;
		
	Возврат Результат;
	
КонецФункции

Функция ПустойИдентификатор()
	Возврат "00000000-0000-0000-0000-000000000000";
КонецФункции

#КонецОбласти

 

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