Предупреждение: материал носит исключительно познавательный характер.
Автор не предлагает делать так, как описано в статье, — он лишь проверил гипотезу и показал результат проверки.
Я уже рассказывал про WebSocket в двух статьях:
- Поинтегрируем: WebSocket’ы в платформе 1С. Часть 1
- Поинтегрируем: WebSocket’ы в платформе 1С. Часть 2
- На Infostart Event Tech 2025 я выступал с докладом по базовому функционалу WebSocket, который появился у нас в версии 8.3.27.
И вроде что ещё говорить?
Но есть одно «но»…
Пока 8 октября 2025 года я сидел и ждал заселения в отель — или хотя бы кого-то из знакомых, чтобы покататься по Неве, — мне в голову пришла гипотеза, которую я решил проверить.
Я достал ноутбук и набросал обработку, а дальше… дальше я расскажу, что из этого вышло.
Суть гипотезы
Заголовки у WebSocket-клиента — это соответствие.

В соответствии мы можем хранить многое, а самое интересное — что мы можем программно создавать столько WebSocket-клиентов, сколько захотим, присваивая им понятные для нас названия ключей. А дальше их можно использовать как константы, не изменяя конфигурацию.
Проверяем гипотезу.
Важное примечание:
WebSocket-клиент — это не соединение.
WebSocket-клиент — это описание параметров подключения к WebSocket-серверу.
Это важно понимать, так как мы будем использовать для хранения значений именно WebSocket-клиент.
1 Добавим WebSocket-клиент
Можно добавить его в основную конфигурацию или расширение.
Я добавлю в расширение:

Обратите внимание: я ничего не прописал в свойствах. Всё, что мне нужно, я заполню программно.
Напоминаю, нас интересуют только заголовки.
2 Предопределим WebSocket-клиент с понятным нам ключом
Нам понадобится имя «WS_Хранилище», которое мы придумали в первом пункте, и ключ.
Ключ WebSocket-клиента – это уникальное строковое значение. По данному значению будет происходить поиск WebSocket-клиента.
Вот так, ключ просто строка, которую написал вручную:

&НаКлиенте
Процедура СоздатьХранилищеЗначений(Команда)
Результат = СоздатьWSХранилище(ИмяВебсокета, КлючВебсокета);
Если Не Результат Тогда
Сообщить("нужно проверить имя объекта метаданных или ключ не уникален");
КонецЕсли;
КонецПроцедуры
// Предопределяем WebSocket-клиент
//
// Параметры:
// ИмяОбъектаМетаданныхWS - Строка - Имя объекта метаданных WebSocket-клиенты
// КлючWS - Строка - Уникальный ключ WebSocket-клиента
//
// Возвращаемое значение:
// Булево - Если Истина WebSocket-клиент предопределен, Ложь нужно проверить имя объекта метаданных или ключ не уникален
//
&НаСервере
Функция СоздатьWSХранилище(Знач ИмяОбъектаМетаданныхWS, Знач КлючWS) Экспорт
Результат = Ложь;
WSОбъектаМетаданных = Метаданные.WebSocketКлиенты.Найти(ИмяОбъектаМетаданныхWS);
Если WSОбъектаМетаданных <> Неопределено Тогда
WSКлиент = WebSocketКлиенты.НайтиПоКлючу(КлючWS);
Если WSКлиент = Неопределено Тогда
WSКлиент = WebSocketКлиенты.СоздатьКлиента(WSОбъектаМетаданных, КлючWS);
WSКлиент.Записать();
Результат = Истина;
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
Пояснение:
Первоначально мы ищем объект метаданных WebSocket-клиенты по имени. Если не находим — значит, ничего не делаем.
Далее мы ищем по ключу WebSocket-клиент. Ключ уникален, и если с таким ключом уже есть запись, тогда мы не сможем предопределить WebSocket-клиент.
Как можно проверить, что мы предопределили WebSocket-клиент?
Например, можно воспользоваться типовой обработкой:

Или выполнить код:
WSКлиент = WebSocketКлиенты.НайтиПоКлючу(КлючWS);
3 Запишем свои значения в предопределенный WebSocket-клиент
Как я уже говорил, будем использовать заголовки.
Для начала запишем несколько значений. Я специально для примера создал справочник «Товары», в котором будет только наименование.
Создам в этом справочнике три элемента:

Также на форме я создам таблицу значения с двумя колонками:

&НаКлиенте
Процедура ЗаписатьЗначения(Команда)
ЗаписатьДанныеWSХранилище(КлючВебсокета);
КонецПроцедуры
// Добавляем данные в предопределенный WebSocket-клиент
//
// Параметры:
// КлючWS - Строка - Уникальный ключ WebSocket-клиента
//
&НаСервере
Процедура ЗаписатьДанныеWSХранилище(Знач КлючWS) Экспорт
ВебсокетКлиент = WebSocketКлиенты.НайтиПоКлючу(КлючWS);
Если ВебсокетКлиент <> Неопределено Тогда
Для Каждого текЭлемент из Список Цикл
ВебсокетКлиент.ПараметрыСоединения.Заголовки.Вставить(текЭлемент.Ключ,текЭлемент.Значение);
КонецЦикла;
ВебсокетКлиент.Записать();
КонецЕсли;
КонецПроцедуры
Пояснение:
Ищем по ключу WebSocket-клиент и вставляем в него заголовки, обходя таблицу значений.
Заполняем ключ ранее предопределенного клиента, добавляем значения и нажимаем «Записать значения»:

И вот тут самое интересное.
Если мы откроем стандартную обработку, то увидим, что ключи и значения с типом строка:

Но это иллюзия 😉
В стандартной обработке просто у таблицы значения колонки с типом строка:

На самом же деле, если мы программно получим значения, то увидим совсем другую картину.
&НаКлиенте
Процедура ПрочитатьДанные(Команда)
ПрочитатьДанныеWSХранилище(КлючВебсокета);
КонецПроцедуры
// Прочитать данные из предопределенного WebSocket-клиент
//
// Параметры:
// КлючWS - Строка - Уникальный ключ WebSocket-клиента
//
&НаСервере
Процедура ПрочитатьДанныеWSХранилище(Знач КлючWS) Экспорт
Если Список.Количество() > 0 Тогда
Список.Очистить();
КонецЕсли;
ВебсокетКлиент = WebSocketКлиенты.НайтиПоКлючу(КлючWS);
Если ВебсокетКлиент <> Неопределено Тогда
Для Каждого текЭлемент из ВебсокетКлиент.ПараметрыСоединения.Заголовки Цикл
новаяСтрока = Список.Добавить();
новаяСтрока.Ключ = текЭлемент.Ключ;
новаяСтрока.Значение = текЭлемент.Значение;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Пояснение:
Очищаем список от введенных ранее значений. Ищем по ключу WebSocket-клиент, заполняем таблицу на основании заголовков WebSocket-клиента.


Как вам такое?
Но мне было интересно зайти дальше…
Мы же можем сохранять хранилище значений, а значит, мы можем записывать в заголовки: структуры, картинки, обработки…
Что угодно.
Давайте проверим
&НаКлиенте
Процедура ЗаписатьСтруктуруВХЗ(Команда)
ЗаписываемаяСтруктура = Новый Структура("Тест,Тест2", 11,"Вася");
НовыйМассив = Новый Массив;
НовыйМассив.Добавить(1);
НовыйМассив.Добавить("текст");
ЗаписываемаяСтруктура.Вставить("МассивДоКучи",НовыйМассив);
ЗаписатьДанныеВЗаголовокПоКлючу(КлючВебсокета, КлючХранилища, ЗаписываемаяСтруктура);
КонецПроцедуры
// Записываем данные в заголовок предопределенного WebSocket-клиента по ключу
//
// Параметры:
// КлючWS - Строка - Уникальный ключ WebSocket-клиента
// КлючЗаголовка - Строка - Имя заголовка
// Значение - Произвольный - Записываемые данные
//
&НаСервере
Процедура ЗаписатьДанныеВЗаголовокПоКлючу(Знач КлючWS, Знач КлючЗаголовка, Знач Значение) Экспорт
ВебсокетКлиент = WebSocketКлиенты.НайтиПоКлючу(КлючWS);
Если ВебсокетКлиент <> Неопределено Тогда
ЗначениеЗаголовка = Новый ХранилищеЗначения(Значение);
ВебсокетКлиент.ПараметрыСоединения.Заголовки.Вставить(КлючЗаголовка, ЗначениеЗаголовка);
ВебсокетКлиент.Записать();
КонецЕсли;
КонецПроцедуры
Пояснение:
Создаем структуру с различными значениями, а далее ищем по ключу WebSocket-клиент и записываем в него новый заголовок с типом ХранилищеЗначения.

А теперь прочитаем, что мы там записали
&НаКлиенте
Процедура ПрочитатьДанныеХЗ(Команда)
Результат = ПрочитатьДанныеЗаголовокаПоКлючу(КлючВебсокета, КлючХранилища);
КонецПроцедуры
// Прочитать данные заголовка по ключу
//
// Параметры:
// КлючWS - Строка - Уникальный ключ WebSocket-клиента
// КлючЗаоловка - Строка - Имя заголовка
//
// Возвращаемое значение:
// Произвольный - значение заголовка
//
&НаСервере
Функция ПрочитатьДанныеЗаголовокаПоКлючу(Знач КлючWS, Знач КлючЗаголовка) Экспорт
Результат = Неопределено;
ВебсокетКлиент = WebSocketКлиенты.НайтиПоКлючу(КлючWS);
Если ВебсокетКлиент <> Неопределено Тогда
ТекущийЗаколовок = ВебсокетКлиент.ПараметрыСоединения.Заголовки[КлючЗаголовка];
Если ТекущийЗаколовок <> Неопределено Тогда
Если ТипЗнч(ТекущийЗаколовок) = Тип("ХранилищеЗначения") Тогда
Результат = ТекущийЗаколовок.Получить();
Иначе
Результат = ТекущийЗаколовок;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции

Хочу добавить, какие фишки у этого метода есть:
1 В отличие от констант тут нет привязки к ролям.
2 Нам не надо лазить в конфигуратор чтобы создать константу.
3 Просто интересная фича.
Очевидные минусы:
1 Непонятно, как это будет в будущем.
2 Незнающий человек долго будет искать, а потом проклинать вас.
3 WebSocket-клиент придуман не для хранилища значений.
Повторюсь: -"Я не призываю так делать".
Я лишь "утолил жажду инженера" и поковырялся чуть дальше, чем нужно 😉
На этом статью заканчиваю, если понравилось, то не стесняйтесь нажимать «+».
Все материалы выложены в GitHub:
Вступайте в нашу телеграмм-группу Инфостарт

