Ко мне часто обращаются заказчики с просьбой «вытащить часть 1С наружу» — например, дать пользователю возможность заполнить поля договора, согласовать цену или уточнить количество товара.
Да, существуют интеграции EDI и B2B, и 1С действительно умеет работать через Apache HTTPD.
Но насколько безопасно и производительно публиковать саму 1С в интернет? Тем более, когда мы живём в эпоху микросервисов, REST API и GraphQL, где системы взаимодействуют через простые протоколы.
Подход
Предположим, нам нужен небольшой специализированный сервис, который выполняет одну задачу — быстро и безопасно.
Например, компания хочет предоставить поставщику возможность заполнить определённые значения позиций в своём заказе, перейдя по ссылке из письма.
Ниже я расскажу, как можно реализовать это с помощью 1С:Управление торговлей 11, Node.js и MySQL.
Архитектура предлагаемого решения

-
В 1С создаётся заказ поставщику.
-
При проведении документа обработчик расширения:
-
формирует JSON с данными заказа (GUID, позиции, количество, цена);
-
отправляет POST-запрос на Node.js API;
-
формирует ссылку вида
https://supplier-app.example.com/edit?orderId={GUID}&key={API_KEY}; -
добавляет ссылку в письмо поставщику.
-
-
Поставщик открывает ссылку, редактирует количество и цены.
-
Node.js сохраняет изменения в MySQL.
-
Регламентное задание 1С раз в час забирает обновления и синхронизирует документ.
1. Настройка 1С
Начнём с кастомизации УТ в части отправки письма со ссылкой на форму для заполнения.
Для таких целей 1С рекомендует создать собственный шаблон электронного письма с формированием через внешнюю обработку.
Шаг 1. Создание обработки с видом «Шаблон сообщения»
Для корректной работы обработки необходимо определить функции:
-
СтруктураДанныхДляОтображенияВШаблоне() -
ПараметрыШаблона() -
СформироватьСообщениеПоШаблону() -
СтруктураДанныхПолучатели()
Наибольший интерес представляет функция СтруктураДанныхДляОтображенияВШаблоне(), которая определяет основные параметры входных и выходных данных:
Функция СтруктураДанныхДляОтображенияВШаблоне() Экспорт
// Создаем структуру данных для шаблона
Структура = Новый Структура;
// Имя типа параметра, на основании которого шаблон создается
Структура.Вставить("ПолноеИмяТипаПараметраВводаНаОсновании", "Заказ поставщику");
// Для электронного письма
Структура.Вставить("ТипТекстаПисьма", Перечисления.СпособыРедактированияЭлектронныхПисем.HTML);
// Заполняем тему и тело письма
Структура.Вставить("ТемаПисьма", "Заказ поставщику");
Структура.Вставить("ТекстШаблонаПисьмаHTML", "");
// Флаги назначения
Структура.Вставить("ПредназначенДляЭлектронныхПисем", Истина);
Структура.Вставить("ПредназначенДляSMS", Ложь);
// Альтернативные тексты (на случай SMS/текста)
Структура.Вставить("ТекстШаблонаSMS", "");
Структура.Вставить("ТекстШаблонаПроизвольный", "");
Возврат Структура;
КонецФункции
Шаг 2. Формирование письма
Функция СформироватьСообщениеПоШаблону() отправляет заказ на Node.js-сервис.
В нашем примере сервер запущен локально (localhost:3000), а эндпоинт /api/orders принимает POST-запрос с сериализованными данными табличной части заказа.
&НаСервере
Функция СформироватьСообщениеПоШаблону(Значения) Экспорт
Сообщение = Новый Структура;
Заказ = Значения.ЗаказПоставщику;
Ответ = ОтправитьЗаказНаСервер(Заказ, "/api/orders");
Если Ответ.HTTP_Response = 200 Тогда
Ссылка = СФормироватьСтрокуUrl("/form/") + Ответ.GUID;
Текст = "<html><body>"
+ "<p>Ссылка на заполнение формы заказа: <a href='" + Ссылка + "'>" + Ссылка + "</a></p>"
+ "</body></html>";
Иначе
ВызватьИсключение("Ошибка отправки заказа на удаленный хост. Ответ: " + Ответ.HTTP_Response);
КонецЕсли;
Сообщение.Вставить("СтруктураВложений", новый Структура);
Сообщение.Вставить("ТемаПисьма", "Заказ поставщику №" + Заказ.Номер + " от " + Формат(Заказ.Дата, "ДЛФ='Д'"));
Сообщение.Вставить("Текст", Текст);
Сообщение.Вставить("ТекстПисьмаHTML", Текст);
Сообщение.Вставить("ТипТекста", Перечисления.СпособыРедактированияЭлектронныхПисем.HTML);
ЗаписатьВРегистрСведенийВGUIDПоставщику(Заказ,Ответ.GUID);
Возврат Сообщение;
КонецФункции
Код процедуры формирования HTTP-запроса и отправки на сервер:
Функция ОтправитьЗаказНаСервер(Заказ,Путь)
// Заказ — объект документа ЗаказПоставщику
// Результат — переменная, в которую вернётся GUID или Неопределено
МассивТоваров = Новый Массив;
Для Каждого СтрокаТовара Из Заказ.Товары Цикл
ДанныеТовара = Новый Структура;
ДанныеТовара.Вставить("item", СтрокаТовара.Номенклатура.Наименование);
ДанныеТовара.Вставить("quantity", СтрокаТовара.Количество);
ДанныеТовара.Вставить("amount", СтрокаТовара.Сумма);
МассивТоваров.Добавить(ДанныеТовара);
КонецЦикла;
ТелоЗапроса = Новый Структура;
ТелоЗапроса.Вставить("doc_number", Заказ.Номер);
ТелоЗапроса.Вставить("doc_date", Формат(Заказ.Дата, "ДФ=yyyy-MM-dd"));
ТелоЗапроса.Вставить("supplier", Заказ.Контрагент.Наименование);
ТелоЗапроса.Вставить("items", МассивТоваров);
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ТелоЗапроса);
СтрокаJSON = ЗаписьJSON.Закрыть();
Результат = Неопределено;
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json");
HTTPСоединение = Новый HTTPСоединение(АдресСервера, Порт);
HTTPЗапрос = Новый HTTPЗапрос(Путь,Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJSON, "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
СтруктураОтвета = новый Структура("HTTP_Response,GUID");
Ответ = HTTPСоединение.ВызватьHTTPМетод("POST", HTTPЗапрос);
СтруктураОтвета.HTTP_Response = Ответ.КодСостояния;
Если Ответ.КодСостояния = 200 Тогда
JSONОтвет = новый ЧтениеJSON();
JSONОтвет.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
РезультатJSON = ПрочитатьJSON(JSONОтвет);
Если ТипЗнч(РезультатJSON) = Тип("Структура") И РезультатJSON.Свойство("guid") Тогда
СтруктураОтвета.GUID = РезультатJSON.guid;
КонецЕсли;
КонецЕсли;
Возврат СтруктураОтвета;
КонецФункции
Шаг 3. Создание шаблона письма
Создаём шаблон сообщения с типом «Сообщение формируется через внешнюю обработку»
(панель Ещё → Внешняя обработка) и указываем ранее созданную обработку epf, предварительно сохраненную в "Печатные формы, отчет и обработки"

Шаг 4. Отправка
Создаём заказ поставщику и нажимаем Отправить->Почта.
После успешной отправки заказа на удалённый сервер и получения GUID заказа во внешней для 1с системе, сама 1С формирует письмо со ссылкой для поставщика

Шаблон сообщения определен непосредственно в коде обработки

2. Веб-приложение обработки заказа
Перейдя по ссылке, поставщик в браузере открывает веб-форму, где может изменить поля Количество и Сумма и сохранить изменения (количество изменений не ограничено):

Обратную синхронизацию с 1С можно реализовать через регламентное задание, которое периодически обращается к API сервиса и обновляет табличные части заказов уже в самой 1С. Код реализации задания выходит за рамки данной статьи.
2.1. Альтернативные принципы обратной связи и организация безопасного обмена
Реализацию обратной связи между внешним приложением и 1С можно выстроить по-разному, в зависимости от инфраструктуры и требований безопасности. Ниже приведу несколько распространённых схем, которые хорошо работают в производственных контурах.
Вариант 1. Прямое взаимодействие через NGINX (Reverse Proxy)
Наиболее очевидный и управляемый способ — разместить промежуточный слой в виде NGINX с включённым reverse proxy и маршрутизацией запросов к внутреннему сервису 1С.
NGINX принимает внешние запросы по HTTPS, проверяет токены (например, JWT или Basic Auth), а затем передаёт только безопасные запросы во внутренний контур.
Такое решение позволяет централизованно управлять авторизацией, логированием и лимитами запросов, не открывая саму 1С наружу.
При необходимости можно подключить WAF-модуль (например, ModSecurity) для фильтрации вредоносных запросов.
Вариант 2. Организация обмена через DMZ-зону
Если корпоративная политика безопасности не допускает прямого доступа к внутренним системам, целесообразно выносить промежуточный API-сервис в DMZ-зону.
В этом случае 1С инициирует исходящее соединение к серверу в DMZ, получая от него новые заказы или статусы обработки.
Такой подход хорош тем, что инициатива обмена всегда принадлежит внутренней системе, и никакие внешние запросы не попадают напрямую во внутренний контур.
Пример схемы:
-
Node.js-сервис в DMZ принимает запросы от пользователей и сохраняет данные в MySQL.
-
Регламентное задание в 1С раз в несколько минут обращается к эндпоинту
/api/updates, получает изменения и синхронизирует их. -
Подтверждённые статусы возвращаются обратно на DMZ-сервер.
3. Node.js и база данных
Для реализации приложения использовались:
-
Node.js 22.19 + Express - лёгкий, устойчивый к нагрузке и хорошо подходящий для микросервисных интеграций с 1С.
Frontend построен на ванильном JavaScript и Bootstrap CSS -
Frontend: ванильный JavaScript и Bootstrap CSS, что позволяет создавать адаптивную форму без тяжёлых фреймворков.
-
База данных: MySQL, поскольку является наиболее употребимой для подобного рода хостингов, но в целом данный DDL совместим и для PostgreSQL
Схема базы данных выглядит следующим образом:
CREATE DATABASE IF NOT EXISTS orders_db;
USE orders_db;
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
guid CHAR(36) NOT NULL,
number VARCHAR(50),
date DATE,
supplier VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE order_items (
id INT AUTO_INCREMENT PRIMARY KEY,
order_guid CHAR(36),
item VARCHAR(255),
quantity DECIMAL(15,2),
amount DECIMAL(15,2),
FOREIGN KEY (order_guid) REFERENCES orders(guid)
);
Данный скрипт необходимо запустить до эксплуатации приложения
Само веб-приложение организовано в виде простого каркаса с разделением на фронтенд, серверный код и вспомогательные модули и наследует паттерн Model-View-Controller

Описание установки node выходит за рамки данной статьи, отмечу лишь зависимости, используемые в проекте:
npm install express mysql2 body-parser dotenv uuid
3.1. Подключение к MySQL
Для доступа к базе используется пакет mysql2 — он поддерживает промисы и хорошо работает с async/await.
// db.js
import mysql from "mysql2/promise";
import dotenv from "dotenv";
dotenv.config();
export const db = await mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
connectionLimit: 5,
});
а вот пример того, как работает роутинг котроллеров для реализации паттерна MVC
import express from "express";
import { v4 as uuidv4 } from "uuid";
import { insertOrder,getOrderByGuid,updateOrderByGuid } from "./db.js";
import path from "path";
import { __dirname, __filename } from "./utils.js";
const router = express.Router();
router.post("/api/orders/create", async (req, res) => {
try {
const data = req.body;
// Generate GUID
const guid = uuidv4();
const order = {
guid,
number: data.doc_number,
date: data.doc_date,
supplier: data.supplier,
items: data.items || [],
};
await insertOrder(order);
res.status(200).json({
status: "ok",
guid,
message: "Order successfully registered",
});
} catch (err) {
console.error("Error processing order:", err);
res.status(500).json({
status: "error",
message: err.message,
});
}
});
// Получение заказа по guid
router.get("/api/orders/:guid", async (req, res) => {
try {
const { guid } = req.params;
const order = await getOrderByGuid(guid);
if (!order || order.length === 0)
return res.status(404).json({ error: "Order not found" });
res.status(200).json({ guid, items: order });
} catch (err) {
console.error("Ошибка при получении заказа:", err);
res.status(500).json({ error: err.message });
}
});
// Обновление заказа по guid
router.post("/api/orders/:guid/save", async (req, res) => {
try {
const { guid } = req.params;
const { items } = req.body;
await updateOrderByGuid(guid, items);
res.status(200).json({ status: "ok" });
} catch (err) {
console.error("Ошибка при обновлении заказа:", err);
res.status(500).json({ error: err.message });
}
});
// === FRONT ===
// Отдача формы по GUID, статика
router.get("/form/:guid", (req, res) => {
res.sendFile(path.join(__dirname, "../public/index.html"));
});
export default router;
Итог
Создан лёгкий сервис, который изолирует 1С от внешней среды, использует стандартные веб-протоколы и позволяет внешним пользователям безопасно взаимодействовать с данными, не нарушая внутреннюю архитектуру компании.
Проверено на следующих конфигурациях и релизах:
- Управление торговлей, редакция 11, релизы 11.5.23.68, 11.5.23.66
Вступайте в нашу телеграмм-группу Инфостарт
