JavaScript из кода 1С:Предприятия: ScriptControl, Node.js и поле HTML
Содержание
Встроенный язык 1С не умеет исполнять JavaScript сам: метод Выполнить() понимает только код на языке 1С. Запустить JavaScript в 1С:Предприятии можно четырьмя путями: через COM-объект MSScriptControl.ScriptControl (движок JScript в Windows), через внешний скрипт cscript или node, запущенный из 1С, через поле HTML-документа на управляемой форме и через HTTP-запрос к отдельному сервису на Node.js.
Выбор зависит от того, где выполняется код (клиент или сервер), какая разрядность у процесса 1С и какой JavaScript нужен: старый JScript уровня ES3 или современный с let, стрелочными функциями и npm-пакетами. Ниже по каждому способу рабочий пример и ограничения, о которые обычно спотыкаются.
Как 1С взаимодействует с JavaScript: четыре схемы
Все способы делятся на две группы. В первой JavaScript исполняется внутри процесса 1С или рядом с ним на той же машине. Во второй — в отдельном процессе, с которым 1С обменивается данными.
- 🧩 ScriptControl — JScript выполняется прямо в процессе 1С через COM. Быстро, без файлов, но только Windows и только 32-битный процесс.
- 📄 Внешний скрипт — 1С пишет данные во временный файл или командную строку, запускает
cscript.exeилиnode.exeи читает результат. Работает с любым JavaScript, но каждый вызов — это новый процесс. - 🖥️ Поле HTML-документа — JavaScript живёт в странице, встроенной в форму. Нужен для интерфейса: графики, карты, редакторы. Исполняется только на клиенте.
- 🌐 HTTP-сервис на Node.js — постоянно запущенный сервер принимает JSON от 1С и отвечает JSON. Самая надёжная схема для серверного кода и тяжёлых библиотек.
COM-объекты доступны только там, где 1С работает под Windows: толстый и тонкий клиент, сервер 1С на Windows, внешнее соединение. В веб-клиенте и на сервере под Linux COM нет, там остаются поле HTML и HTTP.
Запуск JavaScript через COM-объект ScriptControl
MSScriptControl.ScriptControl — компонент Windows (файл msscript.ocx), который исполняет VBScript и JScript. Из 1С он создаётся как обычный COM-объект.
Скрипт = Новый COMОбъект("MSScriptControl.ScriptControl");
Скрипт.Language = "JScript";
Скрипт.AllowUI = Ложь; // запрет окон alert и диалогов
Скрипт.Timeout = 5000; // лимит выполнения, мс
Скрипт.AddCode("function add(a, b) { return a + b; }");
Сумма = Скрипт.Run("add", 2, 3); // 5
Степень = Скрипт.Eval("Math.pow(2, 10)"); // 1024
Три метода закрывают почти все задачи:
| Метод | Что делает | Когда использовать |
|---|---|---|
AddCode(Текст) | Загружает функции и переменные в контекст | Один раз в начале, затем вызывать функции |
Run(Имя, Пар1, Пар2…) | Вызывает функцию по имени с параметрами | Основной способ передать данные из 1С |
Eval(Выражение) | Вычисляет выражение и возвращает значение | Короткие формулы, проверки |
ExecuteStatement(Текст) | Выполняет оператор без возврата значения | Изменение глобальных переменных скрипта |
Ограничения JScript
Движок ScriptControl — это JScript, близкий к стандарту ES3. Код из современных примеров в нём не заработает:
- ❌ нет
let,const, стрелочных функций, шаблонных строк, классов; - ❌ нет встроенного объекта
JSON— сериализацию придётся писать вручную или подключать готовую реализацию черезAddCode; - ❌ нет
requireи npm-модулей; - ✅ есть
Math,RegExp,Date, строковые и массивные методы ES3.
Простые типы (Число, Строка, Булево) передаются в обе стороны без преобразований. Массив JavaScript в 1С приходит как COM-объект, а не как Массив. Проще всего вернуть из функции строку с разделителями и разобрать её через СтрРазделить().
Главная ловушка: разрядность
msscript.ocx существует только в 32-битной версии. В 64-битном клиенте или на 64-битном сервере 1С конструктор падает с ошибкой:
Ошибка при вызове конструктора (COMОбъект): -2147221005(0x800401F3): Недопустимая строка с указанием класса
Варианты решения:
- Запускать код в 32-битном клиенте 1С, если он выполняется на клиенте (
&НаКлиенте). - На сервере перейти на внешний скрипт или HTTP-сервис из следующих разделов.
- Использовать сторонние 64-битные реализации ScriptControl — это внешний компонент, его нужно регистрировать на каждой машине и проверять у себя.
ScriptControl исполняет код с правами процесса 1С. Строку, которую ввёл пользователь, нельзя склеивать с текстом для AddCode или Eval: это прямой путь к выполнению чужого кода. Передавайте данные только параметрами Run.
Вызов внешних JS-скриптов через WScript.Shell и Node.js
Если нужен современный JavaScript или код уже лежит в файле, 1С запускает его как внешнюю программу. Под Windows это делают через COM-объект WScript.Shell.
Пример: скрипт Node.js с результатом в файле
Скрипт C:\scripts\calc.js читает входной JSON, считает и пишет ответ:
// node calc.js вход.json выход.json
const fs = require('fs');
const [, , inFile, outFile] = process.argv;
const data = JSON.parse(fs.readFileSync(inFile, 'utf8'));
const result = { total: data.items.reduce((s, x) => s + x.price * x.qty, 0) };
fs.writeFileSync(outFile, JSON.stringify(result), 'utf8');
process.exit(0);
Код 1С готовит файлы, запускает Node.js, ждёт завершения и читает ответ:
ФайлВход = ПолучитьИмяВременногоФайла("json");
ФайлВыход = ПолучитьИмяВременногоФайла("json");
Позиция = Новый Структура("price, qty", 150, 4);
Позиции = Новый Массив;
Позиции.Добавить(Позиция);
Запись = Новый ЗаписьJSON;
Запись.ОткрытьФайл(ФайлВход, "UTF-8", Ложь);
ЗаписатьJSON(Запись, Новый Структура("items", Позиции));
Запись.Закрыть();
Команда = СтрШаблон("node ""C:\scripts\calc.js"" ""%1"" ""%2""", ФайлВход, ФайлВыход);
Шелл = Новый COMОбъект("WScript.Shell");
КодВозврата = Шелл.Run(Команда, 0, Истина); // 0 — без окна, Истина — ждать
Если КодВозврата = 0 Тогда
Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл(ФайлВыход, "UTF-8");
Ответ = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
Сообщить(Ответ.total); // 600
КонецЕсли;
УдалитьФайлы(ФайлВход);
УдалитьФайлы(ФайлВыход);
Третий параметр Ложь в ОткрытьФайл у ЗаписьJSON отключает BOM. Без этого JSON.parse в Node.js споткнётся о невидимый символ в начале файла.
Почему через файлы, а не через вывод консоли
У WScript.Shell есть метод Exec, который даёт доступ к StdOut. У него два недостатка:
- он всегда показывает окно консоли, скрыть его нельзя;
- вывод читается в OEM-кодировке Windows, и кириллица из Node.js превращается в набор символов.
Файлы в UTF-8 снимают обе проблемы. Для чистого JScript без Node.js работает та же схема, только команда другая: cscript //nologo //E:jscript "C:\scripts\calc.js".
Тот же запуск без COM делает метод платформы ЗапуститьПриложение(Команда, Каталог, ДождатьсяЗавершения, КодВозврата). Он не зависит от WScript.Shell, но окно консоли при запуске может мелькнуть.
Пропишите в команде полный путь к node.exe, если служба сервера 1С работает под отдельной учётной записью: переменная PATH у неё может не содержать каталог Node.js. Скрипт и временный каталог должны быть доступны этой учётной записи.
JavaScript в поле HTML-документа на форме
Когда JavaScript нужен для интерфейса — нарисовать график, показать карту, подключить редактор — его кладут в HTML-страницу и выводят на форме. На управляемой форме это реквизит типа Строка и элемент с видом «Поле HTML-документа».
Страницу с функцией формируют в коде и присваивают реквизиту:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ТекстHTML = "<html><head><script>
|function showTotal(sum) {
| document.getElementById('out').innerText = 'Итого: ' + sum;
|}
|</script></head><body><div id='out'></div></body></html>";
КонецПроцедуры
Вызывать функцию страницы можно только после того, как документ загрузится. Для этого у элемента есть событие ДокументСформирован:
&НаКлиенте
Процедура ТекстHTMLДокументСформирован(Элемент)
Элементы.ТекстHTML.Документ.defaultView.showTotal(600);
КонецПроцедуры
Свойство Документ возвращает DOM страницы, defaultView — её окно, через него доступны глобальные функции JavaScript. Обратная связь из JavaScript в 1С идёт через событие ПриНажатии: скрипт программно «кликает» по скрытому элементу, а в 1С параметр ДанныеСобытия показывает, какой элемент сработал.
Движок поля HTML зависит от версии платформы и операционной системы: это может быть встроенный WebKit или компонент Internet Explorer. Проверяйте скрипт на той платформе, где работают пользователи. В веб-клиенте страница исполняется браузером пользователя.
Сравнение методов интеграции 1С и JavaScript
| Способ | Где работает | Версия JS | Скорость вызова | Главный риск |
|---|---|---|---|---|
| ScriptControl | Windows, 32-битный процесс | JScript (ES3) | Высокая, без запуска процессов | Нет 64-битной версии |
| WScript.Shell + node | Windows, клиент и сервер | Любая, npm | Низкая: новый процесс на вызов | Права учётной записи службы |
| Поле HTML-документа | Только клиент, включая веб | Зависит от движка | Высокая | Разное поведение движков |
| HTTP к Node.js | Любая ОС, клиент и сервер | Любая, npm | Средняя, процесс уже запущен | Нужно держать сервис запущенным |
HTTP-обмен 1С с сервисом на Node.js
Для серверного кода это самая устойчивая схема: Node.js запущен постоянно, 1С отправляет POST с JSON и получает ответ. Работает одинаково на Windows и Linux, не зависит от COM и разрядности.
Минимальный сервис без сторонних пакетов:
const http = require('http');
http.createServer((req, res) => {
if (req.method !== 'POST' || req.url !== '/calc') {
res.writeHead(404);
return res.end();
}
let body = '';
req.on('data', chunk => { body += chunk; });
req.on('end', () => {
try {
const data = JSON.parse(body);
const total = data.items.reduce((s, x) => s + x.price * x.qty, 0);
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({ total }));
} catch (e) {
res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({ error: e.message }));
}
});
}).listen(3000, '127.0.0.1');
Вызов из 1С (можно на сервере):
Позиции = Новый Массив;
Позиции.Добавить(Новый Структура("price, qty", 150, 4));
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, Новый Структура("items", Позиции));
ТекстЗапроса = Запись.Закрыть();
Соединение = Новый HTTPСоединение("127.0.0.1", 3000, , , , 10); // таймаут 10 с
Запрос = Новый HTTPЗапрос("/calc");
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(ТекстЗапроса, КодировкаТекста.UTF8,
ИспользованиеByteOrderMark.НеИспользовать);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 200 Тогда
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
Результат = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
Сообщить(Результат.total); // 150 × 4 = 600
Иначе
ВызватьИсключение СтрШаблон("Сервис вернул код %1: %2",
Ответ.КодСостояния, Ответ.ПолучитьТелоКакСтроку());
КонецЕсли;
Чтобы сервис не падал вместе с консолью, его запускают как службу: в Windows через NSSM или аналог, в Linux через systemd. Если Node.js стоит на другой машине, добавьте HTTPS (ЗащищенноеСоединениеOpenSSL в параметрах HTTPСоединение) и проверку токена в заголовке.
Если обмен идёт в обратную сторону — Node.js сам обращается к 1С, — в конфигурации публикуют HTTP-сервис или используют стандартный OData-интерфейс. Это отдельная настройка публикации базы на веб-сервере.
Ошибки запуска и защита данных
Любой вызов внешнего кода оборачивайте в Попытка … Исключение и пишите ОписаниеОшибки() в журнал регистрации. Пользователь должен видеть понятное сообщение, а не текст COM-исключения.
Правила безопасности
- 🔒 Не собирайте командную строку и код JavaScript из пользовательского ввода. Данные — только через параметры функции, файл или тело запроса.
- 🔒 Сервис Node.js на той же машине слушает
127.0.0.1, а не все интерфейсы. Снаружи он доступен только через HTTPS и с токеном. - 🔒 Ставьте таймауты везде:
Timeoutу ScriptControl, последний параметрHTTPСоединение. Зависший скрипт не должен держать сеанс 1С. - 🔒 Удаляйте временные файлы сразу после чтения: в них могут оказаться персональные данные или суммы.
- 🔒 Во внешних обработках, подключённых в безопасном режиме, создание COM-объектов и запуск программ запрещены. Если в базе включены профили безопасности, нужное разрешение выдаёт администратор.
Частые вопросы
Можно ли выполнить JavaScript методом Выполнить() в 1С?
Выполнить() и Вычислить() работают только с кодом на встроенном языке 1С. Для JavaScript нужен внешний движок: ScriptControl, Node.js или браузерный движок поля HTML.Работает ли ScriptControl на сервере 1С под Linux?
Можно ли подключить npm-пакет к коду 1С напрямую?
Чем JScript в ScriptControl отличается от JavaScript в браузере?
let, const, стрелочных функций, классов и объекта JSON. Код из современных примеров приходится переписывать на var и обычные функции.Как вернуть из JavaScript в 1С несколько значений?
ЧтениеJSON и ПрочитатьJSON() в структуру. Для ScriptControl без встроенного JSON подойдёт строка с разделителем и СтрРазделить().