При разработке на платформе 1С:Предприятие 8.3.16 часто возникает задача разграничения функционала в зависимости от того, каким образом пользователь подключился к базе, например, для задачи копирования файлов и каталогов между Клиентом и Сервером. Одной из наиболее критичных ситуаций является работа с файловой системой. Веб-клиент имеет ряд ограничений по сравнению с тонким или толстым клиентом, поэтому часто требуется алхимический способ работы с двоичными данными, так как попытка выполнить прямой доступ к файлам в браузере без установленного расширения работы с файлами может привести к ошибке. Рассмотрим подробнее, как корректно определить, что пользователь работает через браузер, и как правильно организовать код для блокировки определенных действий.
Первый и самый быстрый способ — это использование директив препроцессора. Важно понимать, что директивы #Если ВебКлиент Тогда работают на этапе компиляции модуля, что учитывает статический анализатор кода проектов. Это означает, что если условие ложно, код внутри него просто не будет включен в скомпилированный образ модуля для данного типа клиента.
Разберем ситуацию: почему у некоторых разработчиков этот метод "не отрабатывает"? Основная причина — контекст выполнения. Директива ВебКлиент доступна только в тех программных модулях (или их частях), которые компилируются на стороне клиента. Если вы попытаетесь использовать её в серверном модуле, она всегда будет возвращать Ложь, так как сервер — это не веб-клиент.
Проанализируем правильный пример использования директивы в модуле формы:
&НаКлиенте
Процедура ПроверитьТипКлиента()
#Если ВебКлиент Тогда
Сообщить("Вы работаете через браузер. Доступ к локальным файлам ограничен!");
// Здесь можно отключить доступность кнопок или выдать предупреждение
#Иначе
Сообщить("Вы работаете через установленный клиент 1С.");
// Разрешаем операции с файлами
#КонецЕсли
КонецПроцедуры
Важное замечание: Директива ВебКлиент появилась еще в версии 8.2, поэтому на платформе 8.3.16 она работает абсолютно штатно. Если ваш код "пролетает" мимо условия, убедитесь, что процедура помечена аннотацией &НаКлиенте.
Если вам необходимо проверять тип клиента динамически или передавать это состояние на сервер, можно воспользоваться анализом текущего сеанса. Начиная с версии 8.3.20, появился удобный метод ТипКлиентскогоПриложения(), но в версии 8.3.16 мы вынуждены использовать альтернативные пути.
Одним из надежных способов на стороне сервера является использование метода ПолучитьТекущийСеансИнформационнойБазы(). У объекта сеанса есть свойство ИмяПриложения, которое однозначно идентифицирует клиента.
Рассмотрим, какие значения может принимать это свойство:
Пример серверной функции для проверки:
&НаСервереБезКонтекста
Функция ЭтоВебКлиентСервер()
Сеанс = ПолучитьТекущийСеансИнформационнойБазы();
Возврат Сеанс.ИмяПриложения = "WebClient";
КонецФункции
Однако помните, что вызов ПолучитьТекущийСеансИнформационнойБазы() — это ресурсоемкая операция, так как она обращается к менеджеру кластера. Не рекомендуется использовать её в часто вызываемых обработчиках, таких как ПриАктивизацииСтроки.
Чтобы не нагружать систему постоянными проверками, правильнее всего определить тип клиента один раз при запуске системы и сохранить его в Параметры сеанса. Выясним, как это реализовать по шагам:
ПараметрСеанса с именем ЭтоВебКлиент (тип: Булево).ПриНачалеРаботыСистемы добавьте проверку.
&НаКлиенте
Процедура ПриНачалеРаботыСистемы()
ЯвляетсяВебКлиентом = Ложь;
#Если ВебКлиент Тогда
ЯвляетсяВебКлиентом = Истина;
#КонецЕсли
// Передаем значение на сервер для установки параметра сеанса
УстановитьПараметрСеансаТипКлиента(ЯвляетсяВебКлиентом);
КонецПроцедуры
Теперь в любой части кода (и на клиенте, и на сервере) вы сможете быстро проверить значение через ПараметрыСеанса.ЭтоВебКлиент, что будет работать мгновенно.
В тексте обсуждения упоминалось использование проверки в событии СписокПриАктивизацииСтроки. Это очень "опасное" место. Данное событие срабатывает при каждом перемещении курсора по списку. Если внутри него будет находиться серверный вызов (даже неявный), интерфейс пользователя начнет заметно "тормозить".
Посмотрим, как оптимизировать код в этом случае. Вместо прямого вызова процедур проверки, лучше использовать ПодключитьОбработчикОжидания. Это позволит системе выполнить проверку только после того, как пользователь зафиксирует курсор на строке на короткое время.
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
// Отключаем предыдущий вызов, если пользователь быстро листает список
ОтключитьОбработчикОжидания("ВыполнитьОбновлениеДоступности");
// Запускаем проверку через 0.1 - 0.2 секунды
ПодключитьОбработчикОжидания("ВыполнитьОбновлениеДоступности", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьОбновлениеДоступности()
#Если ВебКлиент Тогда
// Блокируем команды работы с файлами
Элементы.ГруппаФайловыеКоманды.Доступность = Ложь;
#Иначе
// Разрешаем доступ
Элементы.ГруппаФайловыеКоманды.Доступность = Истина;
#КонецЕсли
КонецПроцедуры
Еще один способ, который иногда используют разработчики — анализ строки соединения информационной базы через функцию СтрокаСоединенияИнформационнойБазы(). Для веб-клиента она будет содержать протоколы http или https.
Проанализируем пример:
СтрокаСоед = СтрокаСоединенияИнформационнойБазы();
Если Найти(СтрокаСоед, "ws=") > 0 Или Найти(СтрокаСоед, "url=") > 0 Тогда
// Вероятно, это веб-подключение
КонецЕсли;
Будьте осторожны: Тонкий клиент также может работать через веб-сервер по протоколу HTTP. В этом случае строка соединения будет похожа на веб-клиентскую, но возможности работы с файлами у тонкого клиента останутся. Поэтому данный метод менее точен, чем директива препроцессора.
Для надежной работы в 1С 8.3.16 рекомендуем комбинированный подход: используйте директиву #Если ВебКлиент в клиентских модулях для быстрой логики интерфейса и Параметры сеанса для глобальных проверок на стороне сервера. Избегайте тяжелых вызовов в обработчиках ожидания и событиях списков, чтобы сохранить высокую скорость работы веб-интерфейса.