Как передать данные из веб-формы в 1С «на лету» через HTTP-сервис?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции 1С с веб-сайтами и внешними интерфейсами разработчики часто сталкиваются с классической архитектурной проблемой: как передать данные, введенные пользователем на сайте, в базу 1С мгновенно (в режиме реального времени) и сразу вернуть обработанный результат назад на форму. В этой статье мы подробно разберем, почему стандартные подходы с простой привязкой переменных не работают, как правильно организовать клиент-серверное взаимодействие и напишем готовое решение с использованием технологии AJAX (Fetch API) на стороне браузера и HTTP-сервиса на стороне 1С.

Анализ проблемы: почему данные не попадают в 1С при вводе?

Рассмотрим ситуацию, в которой оказался автор темы. На веб-странице есть текстовое поле ввода (например, для ввода контрагента). Разработчик хочет, чтобы сразу после окончания ввода система отправляла текст в 1С, находила связанный договор и автоматически заполняла соседнее поле на форме. Однако данные в 1С появляются только тогда, когда пользователь переходит на другую страницу или отправляет всю форму целиком.

Выясним причину такого поведения. Это происходит из-за недопонимания принципов работы веб-технологий и клиент-серверной архитектуры:

  1. Разделение сред исполнения: Браузер (клиент) и платформа 1С (сервер) работают в абсолютно разных средах. Код JavaScript выполняется на компьютере пользователя, а код 1С — на сервере. Они не имеют общей оперативной памяти и не могут напрямую перезаписывать переменные друг друга.
  2. Природа HTTP-протокола: HTTP — это протокол типа «запрос-ответ». Сервер 1С не может самостоятельно узнать, что пользователь что-то ввел на сайте, пока браузер не инициирует и не отправит специальный сетевой запрос (GET или POST).
  3. Поведение по умолчанию: Переход на другую страницу или нажатие кнопки «Отправить» вызывает стандартную отправку HTML-формы. В этот момент браузер собирает все заполненные поля и шлет их на сервер 1С. Именно поэтому автор темы видел данные «только при переходе». При обычном изменении поля (событие onchange) сетевой запрос по умолчанию не отправляется, если разработчик не запрограммировал его вручную.

Чтобы решить эту задачу и обеспечить мгновенный обмен данными без перезагрузки страницы, нам понадобится технология асинхронных запросов AJAX (в современном стандарте реализуемая через встроенный в браузеры метод fetch).

---

Шаг 1. Создание и настройка HTTP-сервиса в 1С

Рассмотрим подробнее, как подготовить базу 1С к приему внешних запросов. Для этого в конфигураторе нам необходимо создать новый объект метаданных — HTTP-сервис.

Выполним следующие настройки в конфигураторе:

  1. Создадим новый HTTP-сервис с именем ИнтеграцияСБраузером и зададим корневой URL: integration.
  2. Добавим шаблон URL с именем ОбработкаДанных и шаблоном: /v1/process.
  3. Для этого шаблона создадим метод POST (так как мы будем отправлять данные из веб-формы) и свяжем его с обработчиком в модуле HTTP-сервиса. Назовем функцию-обработчик ОбработатьДанныеPOST.

Теперь напишем код обработчика в модуле HTTP-сервиса. Наша задача — принять входящий JSON-запрос от веб-страницы, извлечь из него переданную строку, выполнить необходимую бизнес-логику в 1С (например, поиск по справочникам или проведение расчетов) и вернуть структурированный JSON-ответ обратно на сайт.


Функция ОбработатьДанныеPOST(Запрос)
    
    // Установим кодировку UTF-8 для корректного чтения кириллицы
    СтрокаJSON = Запрос.ПолучитьТелоКакСтроку("UTF-8");
    
    // Проверим, что запрос не пустой
    Если ПустаяСтрока(СтрокаJSON) Тогда
        Ответ = Новый HTTPСервисОтвет(400);
        Ответ.УстановитьТелоИзСтроки("Пустое тело запроса", "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
        Возврат Ответ;
    КонецЕсли;
    
    // Десериализуем JSON во внутреннюю структуру 1С
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(СтрокаJSON);
    
    Попытка
        ДанныеПриемника = ПрочитатьJSON(Чтение);
        Чтение.Закрыть();
    Исключение
        Чтение.Закрыть();
        Ответ = Новый HTTPСервисОтвет(400);
        Ответ.УстановитьТелоИзСтроки("Некорректный формат JSON", "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
        Возврат Ответ;
    КонецПопытки;
    
    // Извлекаем переданное значение из поля "inputValue"
    ВходноеЗначение = "";
    Если ТипЗнч(ДанныеПриемника) = Тип("Структура") И ДанныеПриемника.Свойство("inputValue") Тогда
        ВходноеЗначение = СокрЛП(ДанныеПриемника.inputValue);
    КонецЕсли;
    
    // Выполняем логику на стороне 1С (например, поиск договора по названию контрагента)
    // Для демонстрации просто сформируем тестовую строку ответа
    ВыходноеЗначение = "";
    Если ЗначениеЗаполнено(ВходноеЗначение) Тогда
        ВыходноеЗначение = "Успешно обработано в 1С: Договор №" + Строка(Формат(ТекущаяДата(), "ДФ=yyMMdd")) + " для " + ВходноеЗначение;
    КонецЕсли;
    
    // Формируем структуру ответа для отправки обратно на сайт
    СтруктураОтвета = Новый Структура;
    СтруктураОтвета.Вставить("success", Истина);
    СтруктураОтвета.Вставить("processedValue", ВыходноеЗначение);
    
    // Сериализуем структуру ответа в JSON-строку
    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку();
    ЗаписатьJSON(Запись, СтруктураОтвета);
    СтрокаОтвета = Запись.Закрыть();
    
    // Формируем HTTP-ответ
    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
    
    // Важно: разрешаем браузеру принимать ответ (настройка CORS)
    Ответ.Заголовки.Вставить("Access-Control-Allow-Origin", "*");
    
    Ответ.УстановитьТелоИзСтроки(СтрокаОтвета, "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
    
    Возврат Ответ;
    
КонецФункции

---

Шаг 2. Верстка HTML и написание JavaScript на стороне веб-страницы

Проанализируем структуру нашей веб-страницы. Нам нужны два элемента управления: поле, куда пользователь вводит данные (источник), и поле, куда 1С должна динамически вернуть результат (приемник). Мы свяжем событие изменения первого поля с отправкой асинхронного фонового запроса.

Ниже представлен готовый код HTML-страницы с интегрированным скриптом на JavaScript, который использует современный стандарт Fetch API для общения с опубликованной базой 1С:


<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Интеграция веб-формы с 1С</title>
    <style>
        .form-group {
            margin-bottom: 15px;
            font-family: Arial, sans-serif;
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        input {
            width: 300px;
            padding: 8px;
            font-size: 14px;
        }
        .loading-indicator {
            display: none;
            color: gray;
            font-size: 12px;
            margin-top: 5px;
        }
    </style>
</head>
<body>

    <div class="form-group">
        <label for="Kontr_Znach">Контрагент (введите значение):</label>
        <input type="text" id="Kontr_Znach" placeholder="Введите название контрагента...">
        <div id="loader" class="loading-indicator">Отправка запроса в 1С...</div>
    </div>

    <div class="form-group">
        <label for="Dog_Znach">Договор (заполняется автоматически):</label>
        <input type="text" id="Dog_Znach" readonly style="background-color: #f0f0f0;">
    </div>

    <script>
        // Находим элементы DOM на форме
        const inputKontr = document.getElementById('Kontr_Znach');
        const inputDog = document.getElementById('Dog_Znach');
        const loader = document.getElementById('loader');

        // URL публикации вашего HTTP-сервиса в 1С
        // Замените "my-web-server" и "my_base" на ваши реальные данные публикации
        const serviceUrl = 'http://my-web-server/my_base/hs/integration/v1/process';

        // Навешиваем обработчик события "change"
        inputKontr.addEventListener('change', async function() {
            const val = inputKontr.value.trim();
            
            // Если поле пустое, очищаем результирующее поле и выходим
            if (!val) {
                inputDog.value = '';
                return;
            }

            // Показываем индикатор загрузки
            loader.style.display = 'block';

            try {
                // Выполняем асинхронный POST запрос к 1С
                const response = await fetch(serviceUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json; charset=utf-8'
                    },
                    body: JSON.stringify({
                        inputValue: val
                    })
                });

                if (response.ok) {
                    const resultData = await response.json();
                    
                    // Если 1С вернула успешный статус, записываем данные в поле Договор
                    if (resultData.success) {
                        inputDog.value = resultData.processedValue;
                    } else {
                        console.error('Ошибка логики 1С');
                        inputDog.value = 'Ошибка обработки данных';
                    }
                } else {
                    console.error('Сетевая ошибка при запросе к 1С. Статус:', response.status);
                    inputDog.value = 'Ошибка связи с сервером';
                }
            } catch (error) {
                console.error('Не удалось выполнить запрос:', error);
                inputDog.value = 'Сервер 1С недоступен';
            } finally {
                // Скрываем индикатор загрузки в любом случае
                loader.style.display = 'none';
            }
        });
    </script>

</body>
</html>

---

Шаг 3. Решение проблемы CORS (Cross-Origin Resource Sharing)

При тестировании этой схемы вы почти наверняка столкнетесь с тем, что браузер блокирует запросы к 1С, а в консоли разработчика (F12) появляется ошибка вида: Access to fetch at ... has been blocked by CORS policy. Это встроенный механизм безопасности браузеров. Если HTML-страница открыта по адресу http://mysite.com, а запрос идет на http://1c-server/base, браузер считает это угрозой безопасности (кросс-доменным запросом) и блокирует его.

Проанализируем, как правильно обойти это ограничение на стороне 1С. Перед тем как отправить основной запрос методом POST, браузер автоматически посылает предварительный проверочный запрос методом OPTIONS (так называемый preflight-запрос). Нам необходимо научить наш HTTP-сервис корректно отвечать на этот запрос.

  1. Добавим в наш шаблон URL ОбработкаДанных новый метод с именем OPTIONS и обработчиком ОбработатьДанныеOPTIONS.
  2. Напишем код обработчика, который будет возвращать пустой ответ с кодом 200, но с правильным набором заголовков безопасности.

Функция ОбработатьДанныеOPTIONS(Запрос)
    
    Ответ = Новый HTTPСервисОтвет(200);
    
    // Разрешаем запросы с любых доменов (в продакшене лучше указать конкретный домен вашего сайта)
    Ответ.Заголовки.Вставить("Access-Control-Allow-Origin", "*");
    
    // Разрешаем отправку заголовков авторизации и типов контента
    Ответ.Заголовки.Вставить("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
    
    // Явно указываем разрешенные методы запроса
    Ответ.Заголовки.Вставить("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    
    Возврат Ответ;
    
КонецФункции

---

Шаг 4. Настройка авторизации на веб-сервере

По умолчанию база 1С закрыта от неавторизованного доступа. Любой HTTP-запрос к ней потребует ввода логина и пароля пользователя 1С. Чтобы веб-сайт мог обращаться к базе в фоновом режиме без постоянного запроса пароля у конечного пользователя сайта, у нас есть два пути:

  1. Анонимный доступ через файл публикации (рекомендуется):
    При публикации базы через Apache или IIS создается конфигурационный файл default.vrd. В нем можно прописать системного пользователя 1С, под которым будут автоматически выполняться все входящие HTTP-запросы. Для этого в файле публикации найдите блок <httpServices> и добавьте параметры авторизации:
    
    <httpServices ibAndHttpBasicAuth="false">
        <service name="ИнтеграцияСБраузером" rootUrl="integration" enable="true" reuseSessions="autouse">
            <credentials user="WebUser" password="WebPassword123" />
        </service>
    </httpServices>
    
    В этом случае запросы из JS будут выполняться мгновенно и безопасно под выделенной служебной учетной записью WebUser.
  2. Передача Basic-авторизации в заголовках JS:
    Мы можем передавать зашифрованные логин и пароль прямо в коде JavaScript в заголовке Authorization. Однако помните, что этот способ крайне небезопасен, так как любой пользователь сможет открыть исходный код страницы в браузере и увидеть ваши учетные данные 1С.

---

Шаг 5. Оптимизация интерфейса: событие oninput и оптимизация задержки (Debounce)

В завершение разберем важное улучшение юзабилити формы. Событие change срабатывает только тогда, когда пользователь убрал фокус ввода из поля (кликнул в другое место страницы или нажал Enter). Если мы хотим сделать интерфейс по-настоящему живым и проверять данные прямо в процессе ввода текста, нам нужно перехватывать событие input.

Но здесь кроется опасность: если отправлять сетевой запрос в 1С при вводе каждого символа, то при быстром наборе слова «Иванов» браузер сделает 6 последовательных запросов в 1С. Это создаст колоссальную и бесполезную нагрузку на сервер. Для решения этой проблемы в веб-разработке применяется паттерн Debounce (устранение дребезга). Запрос отправляется только тогда, когда пользователь сделал паузу в вводе (например, на 500 миллисекунд).

Посмотрим на пример модификации JavaScript кода с использованием Debounce:


// Функция-обертка для задержки вызова
function debounce(func, delay) {
    let timeoutId;
    return function (...args) {
        if (timeoutId) {
            clearTimeout(timeoutId);
        }
        timeoutId = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    };
}

// Навешиваем обработчик на событие "input" с задержкой в 600 мс
inputKontr.addEventListener('input', debounce(async function() {
    const val = inputKontr.value.trim();
    if (!val) {
        inputDog.value = '';
        return;
    }
    
    loader.style.display = 'block';
    
    try {
        const response = await fetch(serviceUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ inputValue: val })
        });
        
        if (response.ok) {
            const resultData = await response.json();
            if (resultData.success) {
                inputDog.value = resultData.processedValue;
            }
        }
    } catch (e) {
        console.error(e);
    } finally {
        loader.style.display = 'none';
    }
}, 600)); // Запрос уйдет в 1С только через 0.6 сек после окончания ввода

Используя данный подход, вы полностью контролируете нагрузку на вашу информационную базу 1С, обеспечивая при этом максимально отзывчивое и современное поведение веб-интерфейса для конечного пользователя.

← На главную