Архитектура "клиент-сервер" в 1С:Предприятие подразумевает постоянный обмен данными между серверной и клиентской частями системы. Но не все типы информации можно передавать напрямую, а некоторые форматы требуют преобразования или оптимизации. Почему это важно? Потому что неправильная передача данных может приводить к задержкам интерфейса, ошибкам выполнения или даже утечкам конфиденциальной информации.
В этой статье разберём, какие именно данные можно передавать с сервера на клиент в различных режимах работы 1С (тонкий клиент, веб-клиент, мобильное приложение), какие форматы поддерживаются "из коробки", а где потребуются обходные решения. Особое внимание уделим ограничениям платформы, методам оптимизации трафика и типичным ошибкам, которые допускают разработчики при проектировании обмена.
Сервер 1С:Предприятия — это не просто хранилище данных, а полноценный обработчик бизнес-логики. Клиентская часть (будь то десктопное приложение или браузер) выступает в роли "витрины", которая отображает результаты вычислений и позволяет пользователю взаимодействовать с системой. Однако не все объекты конфигурации можно передать "как есть" — платформа накладывает жёсткие ограничения на типы данных, сериализацию и объём передаваемой информации.
Например, попытка отправить на клиент объект ДокументОбъект.МодульОбъекта приведёт к ошибке, тогда как массив значений или структура пройдут без проблем. Почему так происходит? Потому что платформа 1С разделяет данные на "сериализуемые" (которые можно преобразовать в поток байтов для передачи) и "несериализуемые" (содержащие исполнимый код или ссылки на внутренние механизмы).
В этой статье мы не будем говорить о низкоуровневых протоколах вроде TCP/IP или HTTP — сфокусируемся на практических аспектах: что именно можно передавать, как это делать эффективно, и где таятся подводные камни. Если вы разрабатываете распределённые системы на 1С или интегрируете её с внешними сервисами, эта информация поможет избежать типичных ошибок и оптимизировать производительность.
1. Типы данных, которые можно передавать с сервера на клиент
Платформа 1С:Предприятие 8 поддерживает передачу ограниченного набора типов данных между сервером и клиентом. Их можно разделить на три основные группы:
1. Примитивные типы — простейшие значения, которые передаются без преобразований:
- 🔢 Число (
Число) — целочисленные и дробные значения. - 📝 Строка (
Строка) — текстовые данные, включая многобайтовые символы (Unicode). - 🗓️ Дата (
Дата) — дата и время, включая миллисекунды. - 🔘 Булево (
Булево) — логические значенияИстина/Ложь. - 🎨 Цвет (
Цвет) — цвет в формате RGB.
2. Составные типы — структуры, которые платформа умеет сериализовать:
- 📋 Массив (
Массив) — одномерные и многомерные массивы примитивов или других сериализуемых объектов. - 🗃️ Структура (
Структура) — ассоциативные массивы с именованными ключами. - 🔗 Соответствие (
Соответствие) — пары "ключ-значение" с произвольными типами ключей. - 📊 Таблица значений (
ТаблицаЗначений) — двумерные таблицы с колонками и строками.
3. Специальные объекты платформы — требуют осторожности при передаче:
- 📄 Ссылка на объект (
Ссылка) — ссылки на документы, справочники, планы счетов и т.д. Передаются только если клиент имеет права на чтение этих объектов. - 🖼️ Картинка (
Картинка) — растровые изображения в форматахBMP,JPEG,PNG. - 📎 Двоичные данные (
ДвоичныеДанные) — файлы, архивы, сериализованные объекты. - 🔑 Уникальный идентификатор (
УникальныйИдентификатор) — GUID-ы для идентификации объектов.
Критично важный нюанс: объекты, содержащие исполнимый код (модули, менеджеры, коллекции объектов с методами), передавать на клиент нельзя. Это правило действует даже для объектов, которые "кажутся" безопасными, например, ДокументОбъект.МодульОбъекта или СправочникОбъект.Форма.
Если вам нужно передать сложный объект, например, документ со всеми реквизитами, используйте механизм "пакетной передачи" через ПоместитьВоВременноеХранилище() или преобразуйте объект в Структуру/ТаблицуЗначений.
2. Методы передачи данных: от простого к сложному
В 1С:Предприятии есть несколько способов передать данные с сервера на клиент. Выбор метода зависит от объёма данных, требований к производительности и архитектуры решения. Рассмотрим основные подходы от самого простого к наиболее сложному.
1. Прямая передача через возвращаемое значение функции
Самый очевидный способ — вернуть данные из серверной функции или процедуры. Подходит для небольших объёмов:
// Серверная функция
Функция ПолучитьДанныеОКлиенте() Экспорт
Возврат Новый Структура("Имя, Возраст, ДатаРождения", "Иван Иванов", 30, '1993-05-15');
КонецФункции
// Клиентский вызов
Данные = Сервер.ПолучитьДанныеОКлиенте();
Ограничения:
- ⚠️ Объём данных не должен превышать 10-15 МБ (точное значение зависит от версии платформы и настроек сервера).
- ⚠️ Сериализация больших объектов (например,
ТаблицаЗначенийс 100 000 строк) может занять несколько секунд.
2. Временное хранилище (ПоместитьВоВременноеХранилище())
Если нужно передать большой объект (например, отчёт в формате ТабличныйДокумент или пакет документов), используйте временное хранилище:
// Сервер: помещаем данные во временное хранилище
Идентификатор = ПоместитьВоВременноеХранилище(Отчет.Сформировать());
// Клиент: получаем данные по идентификатору
Отчет = ПолучитьИзВременногоХранилища(Идентификатор);
Преимущества:
- 🚀 Поддерживает объекты, которые нельзя передать напрямую (например,
ТабличныйДокумент,ГрафическаяСхема). - 🗄️ Данные хранятся на сервере до тех пор, пока клиент их не запросит (или до истечения времени жизни).
3. HTTP-сервисы и REST API
Для интеграции с внешними системами или мобильными клиентами удобно использовать HTTPСервис. Данные передаются в формате JSON или XML:
// Опубликовать HTTP-сервис в конфигураторе
// Пример обработки GET-запроса
Функция ПолучитьСписокТоваров(Запрос) Экспорт
Товары = Новый Массив();
Товары.Добавить(Новый Структура("Наименование, Цена", "Ноутбук", 50000));
Товары.Добавить(Новый Структура("Наименование, Цена", "Смартфон", 30000));
Возврат Новый HTTPСервисОтвет(200, , Новый ЗаписьJSON());
КонецФункции
4. WebSocket для передачи данных в реальном времени
Если нужна мгновенная синхронизация (например, для дашбордов или чатов), используйте WebSocket. В 1С это реализуется через внешние компоненты или расширения:
// Пример клиентского кода на JavaScript для подключения к WebSocket
const socket = new WebSocket("ws://server:port/ws");
socket.onmessage = (event) => {
console.log("Получены данные:", event.data);
};
Сравнение методов передачи данных:
| Метод | Макс. объём данных | Поддерживаемые типы | Скорость | Сложность реализации |
|---|---|---|---|---|
| Прямая передача | до 10-15 МБ | Примитивы, массивы, структуры | ⚡ Быстро | ⭐ Низкая |
| Временное хранилище | до 100 МБ* | Любые сериализуемые объекты | 🐢 Медленнее | ⭐⭐ Средняя |
| HTTP-сервисы | не ограничено** | JSON/XML (примитивы, массивы, структуры) | ⚡ Быстро | ⭐⭐⭐ Высокая |
| WebSocket | не ограничено** | Текстовые данные (JSON) | ⚡⚡ Мгновенно | ⭐⭐⭐⭐ Очень высокая |
* Зависит от настроек сервера 1С:Предприятия и доступной памяти.
** Ограничивается настройками веб-сервера (например, nginx или Apache).
Если передаёте большие ТаблицаЗначений через временное хранилище, предварительно удалите ненужные колонки с помощью Таблица.Колонки.Удалить() — это сократит объём данных на 30-50%.
3. Ограничения и "подводные камни"
Даже если тип данных теоретически можно передать с сервера на клиент, на практике вас могут поджидать неочевидные ограничения. Рассмотрим самые распространённые проблемы и способы их обхода.
1. Ограничения по объёму данных
Платформа 1С неявно ограничивает размер передаваемых данных. Например:
- 📉 При прямой передаче через возвращаемое значение функции лимит составляет ~10 МБ (точное значение зависит от версии платформы).
- 📉 Для временного хранилища лимит по умолчанию — 100 МБ, но его можно увеличить в настройках сервера.
- 📉 В
HTTPСервислимит задаётся настройками веб-сервера (например,client_max_body_sizeв nginx).
⚠️ Внимание: При передаче больших ТаблицаЗначений (более 50 000 строк) платформа может "зависнуть" на этапе сериализации. Решение — разбивать данные на пакеты по 10 000-20 000 строк и передавать их последовательно.
2. Проблемы с правами доступа
Если вы передаёте ссылки на объекты (например, СсылкаНаДокумент), клиент должен иметь права на чтение этих объектов. В противном случае возникнет ошибка:
Ошибка при вызове метода контекста (ПолучитьДанные):
{ОбщийМодуль.МойМодуль.Модуль(18)}: Ошибка при чтении данных объекта!
Права доступа: Чтение
Решение:
- 🔐 Проверяйте права клиента через
ПраваДоступа.ПроверкаПрав()перед передачей данных. - 🔐 Используйте
ОбходПравДоступа(только для администраторов!). - 🔐 Передавайте вместо ссылок только
УникальныйИдентификаторобъекта, а на клиенте загружайте данные по ID.
3. Сериализация сложных объектов
Некоторые объекты 1С нельзя передать напрямую, даже если они "кажутся" простыми. Например:
- ❌
ДокументОбъект.МодульОбъекта— содержит исполнимый код. - ❌
Форма— включает в себя элементы управления и обработчики событий. - ❌
Запрос.Результат— требует преобразования вТаблицаЗначений. - ❌
ПланОбмена.Узел— содержит ссылки на внутренние механизмы синхронизации.
⚠️ Внимание: Если вам нужно передать результат запроса (Запрос.Выполнить().Выгрузить()), сначала преобразуйте его вТаблицаЗначенийс помощью методаВыгрузить(). Иначе клиент получит ошибку сериализации.
4. Проблемы с многопоточностью
В режиме управляемого приложения (тонкий клиент, веб-клиент) все вызовы на сервер выполняются асинхронно. Это означает, что:
- 🔄 Если клиент отправил два запроса подряд, ответы могут прийти в произвольном порядке.
- 🔄 Длинные операции (более 30 секунд) могут быть прерваны по таймауту.
Решение:
- 🔄 Используйте
Ожиданиедля синхронизации асинхронных вызовов. - 🔄 Разбивайте длинные операции на более мелкие шаги.
Как обойти ограничение на передачу Запрос.Результат?
Если вам нужно передать результат запроса на клиент, используйте следующий код:
РезультатЗапроса = Запрос.Выполнить();
ТаблицаДанных = РезультатЗапроса.Выгрузить(); // Преобразуем в ТаблицуЗначений
Возврат ТаблицаДанных;
Это позволит избежать ошибки сериализации, так как ТаблицаЗначений поддерживается клиентской частью.
4. Оптимизация передачи данных: как ускорить обмен
Медленная передача данных между сервером и клиентом — одна из главных причин "тормозов" в 1С. Особенно это заметно в веб-клиенте или при работе по медленным каналам (например, мобильный интернет). Вот несколько способов оптимизации:
1. Передавайте только необходимые данные
Частая ошибка — передача на клиент всех полей объекта, когда нужны только 2-3. Например, вместо того чтобы отправлять весь документ "РеализацияТоваровУслуг", отправляйте только:
Функция ПолучитьКраткуюИнформациюОДокументе(СсылкаНаДокумент) Экспорт
Документ = СсылкаНаДокумент.ПолучитьОбъект();
Возврат Новый Структура(
"Номер, Дата, Сумма, Контрагент",
Документ.Номер,
Документ.Дата,
Документ.СуммаДокумента,
Документ.Контрагент.Наименование
);
КонецФункции
2. Используйте сжатие данных
Для больших массивов или строк можно применять сжатие с помощью СжатьДанные():
// Сервер: сжимаем данные перед отправкой
СжатыеДанные = СжатьДанные(JSON.Записать(БольшойМассив));
// Клиент: распаковываем данные
РаспакованныеДанные = JSON.Прочитать(РазжатьДанные(СжатыеДанные));
3. Кэшируйте часто запрашиваемые данные
Если одни и те же данные запрашиваются многократно (например, справочник контрагентов), кэшируйте их на клиенте:
// Клиентский код
Если Не ЗначениеЗаполнено(КэшКонтрагентов) Тогда
КэшКонтрагентов = Сервер.ПолучитьСписокКонтрагентов();
КонецЕсли;
4. Разбивайте большие пакеты данных
Если нужно передать 100 000 строк, разбивайте их на пакеты по 5 000-10 000 строк и загружайте последовательно:
// Сервер: функция для постраничной загрузки
Функция ПолучитьТоварыПостранично(НомерСтраницы, РазмерСтраницы) Экспорт
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ &РазмерСтраницы
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ Справочник.Номенклатура КАК Номенклатура
|УПОРЯДОЧИТЬ ПО Наименование
|ИНДЕКСИРОВАТЬ ПО НомерСтраницы, РазмерСтраницы";
Запрос.УстановитьПараметр("НомерСтраницы", НомерСтраницы);
Запрос.УстановитьПараметр("РазмерСтраницы", РазмерСтраницы);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
5. Используйте двоичный формат вместо JSON/XML
Для передачи больших объёмов данных (например, отчётов в формате ТабличныйДокумент) эффективнее использовать двоичную сериализацию:
// Сервер: сохраняем отчёт в двоичном формате
ДвоичныеДанные = Новый ЗаписьДанных();
Отчет.Записать(ДвоичныеДанные);
Идентификатор = ПоместитьВоВременноеХранилище(ДвоичныеДанные.Закрыть());
// Клиент: восстанавливаем отчёт
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Идентификатор);
Отчет = Новый ТабличныйДокумент;
Отчет.Прочитать(Новый ЧтениеДанных(ДвоичныеДанные));
☑️ Оптимизация передачи данных в 1С
5. Безопасность передачи данных: что нужно учитывать
Передача данных с сервера на клиент — это не только вопрос производительности, но и безопасности. Неправильная организация обмена может привести к утечке конфиденциальной информации или несанкционированному доступу к данным.
1. Проверка прав доступа
Всегда проверяйте, имеет ли клиент право на доступ к запрашиваемым данным. Например, перед передачей списка документов убедитесь, что пользователь имеет право их просматривать:
Функция ПолучитьСписокДокументов() Экспорт
Если Не ПраваДоступа.ПроверкаПрав("Документ.РеализацияТоваровУслуг", "Чтение") Тогда
Возврат Новый Структура("Ошибка", "Недостаточно прав для просмотра документов");
КонецЕсли;
// ... код получения данных
КонецФункции
2. Фильтрация чувствительных данных
Никогда не передавайте на клиент пароли, токены авторизации или персональные данные (например, паспортные данные сотрудников) в открытом виде. Используйте маскирование или шифрование:
// Пример маскирования номера телефона
Функция ЗамаскироватьТелефон(Телефон) Экспорт
Если СтрДлина(Телефон) > 4 Тогда
Возврат "*" + Сред(Телефон, СтрДлина(Телефон) - 3);
Иначе
Возврат Телефон;
КонецЕсли;
КонецФункции
3. Защита от CSRF-атак
Если вы используете HTTPСервисы, обязательно настройте защиту от межсайтовой подделки запросов (CSRF). В 1С это делается через проверку специального токена:
// Пример проверки CSRF-токена в HTTP-сервисе
Функция ОбработатьЗапрос(Запрос) Экспорт
Если Запрос.Заголовки.Найти("X-CSRF-Token") = Неопределено Тогда
Возврат Новый HTTPСервисОтвет(403, "Отсутствует CSRF-токен");
КонецЕсли;
// Проверяем токен (в реальном коде нужно сравнить с сохранённым значением)
Если Запрос.Заголовки.Pолучить("X-CSRF-Token") <> СохраненныйТокен Тогда
Возврат Новый HTTPСервисОтвет(403, "Неверный CSRF-токен");
КонецЕсли;
// Обработка запроса
КонецФункции
4. Шифрование данных
Если данные передаются по незащищённым каналам (например, через HTTP вместо HTTPS), используйте дополнительное шифрование:
// Пример симметричного шифрования (AES)
Функция ЗашифроватьДанные(Данные, Ключ) Экспорт
Шифровщик = Новый ШифрованиеДанных("AES");
Шифровщик.УстановитьКлюч(Ключ);
Возврат Шифровщик.Зашифровать(Данные);
КонецФункции
Функция РасшифроватьДанные(Данные, Ключ) Экспорт
Шифровщик = Новый ШифрованиеДанных("AES");
Шифровщик.УстановитьКлюч(Ключ);
Возврат Шифровщик.Расшифровать(Данные);
КонецФункции
⚠️ Внимание: При использовании шифрования убедитесь, что ключ хранится в безопасном месте (например, в ХранилищеНастроек с ограниченным доступом). Не передавайте ключ вместе с зашифрованными данными!
5. Логирование и аудит
Ведите журнал передачи конфиденциальных данных. Это поможет отследить возможные утечки:
// Пример логирования доступа к данным
Процедура ЗаписатьВЖурнал(Пользователь, ТипДанных, Действие) Экспорт
Лог = Новый ТекстовыйДокумент;
Лог.ДобавитьСтроку(ТекущаяДата() + " | " + Пользователь + " | " + ТипДанных + " | " + Действие);
Лог.Записать("C:\Logs\DataAccess.log", КодировкаТекста.UTF8, РежимЗаписиТекста.Добавление);
КонецПроцедуры
Всегда проверяйте права доступа на сервере, даже если клиент "уверяет", что у него есть доступ. Клиентские данные можно подделать, а серверная проверка — единственный надёжный барьер.
6. Примеры кода: передача различных типов данных
В этом разделе собраны готовые примеры кода для передачи различных типов данных с сервера на клиент. Вы можете использовать их как шаблоны для своих задач.
Пример 1: Передача структуры с примитивными типами
// Сервер
Функция ПолучитьИнформациюОПользователе() Экспорт
Возврат Новый Структура(
"Имя, Возраст, ДатаРождения, Активен",
"Алексей Петров",
28,
'1995-06-20',
Истина
);
КонецФункции
// Клиент
Пользователь = Сервер.ПолучитьИнформациюОПользователе();
Сообщить(Пользователь.Имя); // Выведет: Алексей Петров
Пример 2: Передача таблицы значений с постраничной загрузкой
// Сервер
Функция ПолучитьТовары(НомерСтраницы, РазмерСтраницы) Экспорт
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ &РазмерСтраницы
| Товар.Ссылка КАК Ссылка,
| Товар.Наименование КАК Наименование,
| Товар.Цена КАК Цена
|ИЗ Справочник.Номенклатура КАК Товар
|УПОРЯДОЧИТЬ ПО Наименование
|ИНДЕКСИРОВАТЬ ПО НомерСтраницы, РазмерСтраницы";
Запрос.УстановитьПараметр("НомерСтраницы", НомерСтраницы);
Запрос.УстановитьПараметр("РазмерСтраницы", РазмерСтраницы);
Результат = Запрос.Выполнить();
Возврат Результат.Выгрузить();
КонецФункции
// Клиент
Товары = Сервер.ПолучитьТовары(1, 50); // Первая страница, 50 товаров
Пример 3: Передача двоичных данных (файла)
// Сервер: читаем файл и передаём его клиенту
Функция ПолучитьФайлОтчета() Экспорт
ПутьКФайлу = "C:\Reports\report.xlsx";
ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
Возврат ДвоичныеДанные;
КонецФункции
// Клиент: сохраняем файл на диск
ДанныеФайла = Сервер.ПолучитьФайлОтчета();
ДанныеФайла.Записать("C:\Temp\report_download.xlsx");
Пример 4: Передача результата запроса через временное хранилище
// Сервер
Функция ПолучитьБольшойОтчет() Экспорт
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Клиент.Наименование КАК Клиент,
| СУММА(Документ.СуммаДокумента) КАК Сумма
|ИЗ Документ.РеализацияТоваровУслуг КАК Документ
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты