Как отправить POST-запрос из HTML в 1С, пройти авторизацию и получить файл Excel?

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

В рамках данной статьи мы подробно рассмотрим процесс интеграции HTML-страницы с HTTP-сервисом 1С, охватывая вопросы отправки POST-запросов, методов авторизации и эффективного получения файлов Excel. Мы выясним, как преодолеть типичные сложности, такие как CORS, и обеспечим корректное взаимодействие между клиентской частью и серверной логикой 1С.

Основные сложности при отправке POST-запроса из HTML в 1С

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

  1. Авторизация: Стандартные HTML-формы не предоставляют простого механизма для добавления HTTP-заголовков, в том числе для Basic-авторизации. Это приводит к тому, что запросы приходят в 1С без необходимых учетных данных и требуют авторизации, что является основным барьером для прямого взаимодействия.
  2. Получение файла Excel: Когда 1С формирует и отправляет в ответ бинарные данные (например, файл Excel), браузер не автоматически обрабатывает этот поток как скачиваемый файл, если запрос был отправлен через JavaScript (например, с помощью fetch или XMLHttpRequest). Требуется дополнительная логика на стороне клиента для инициирования загрузки.
  3. CORS (Cross-Origin Resource Sharing): Это критический механизм безопасности браузеров. Если ваша HTML-страница размещена на одном домене (например, mywebsite.com), а HTTP-сервис 1С доступен на другом домене (или даже на другом порту того же IP-адреса), браузер по умолчанию заблокирует междоменный запрос. Это распространенная проблема, которую необходимо решать на стороне HTTP-сервиса 1С.
  4. Предварительный запрос (Preflight OPTIONS): Современные браузеры, следуя спецификации CORS, перед отправкой "сложных" запросов (например, POST-запросов с нестандартными заголовками или с типом контента, отличным от application/x-www-form-urlencoded, multipart/form-data или text/plain) сначала отправляют предварительный запрос методом OPTIONS. Если ваш HTTP-сервис в 1С не умеет обрабатывать этот метод и не возвращает пустой ответ с кодом 200 и нужными CORS-заголовками, основной POST-запрос даже не будет отправлен.

Методы авторизации HTTP-сервиса 1С

Рассмотрим несколько подходов для прохождения авторизации при обращении к HTTP-сервису 1С из веб-интерфейса. Выбор метода зависит от требований к безопасности и сложности реализации.

  1. Отключение авторизации через файл vrd

    Этот метод является наиболее простым, если вы готовы, чтобы HTTP-сервис работал от имени конкретного пользователя 1С без явного запроса пароля от клиента. Это полезно для внутренних систем или когда безопасность контролируется на уровне веб-сервера.

    Для реализации этого подхода откройте файл default.vrd (или файл с именем вашего сервиса, например, мойсервис.vrd) в папке публикации вашего HTTP-сервиса на веб-сервере. Внутри тега <v8:point> вам необходимо добавить или изменить параметр <v8:userName>, указав имя пользователя 1С, под которым будут выполняться все запросы к этому сервису.

    
    <?xml version="1.0" encoding="UTF-8"?>
    <v8:point xmlns:v8="http://v8.1c.ru/8.3/data/point">
        <v8:base ref="имя_вашей_базы" alias="имя_вашей_базы"/>
        <v8:userName>ИмяПользователя1С</v8:userName>
        <v8:app name="e1cib/http/ваш_сервис" connectionString="Srvr="ИмяСервера1С";Ref="ИмяБазы1С";"/>
    </v8:point>
    

    После внесения изменений в файл vrd обязательно перезапустите веб-сервер (например, IIS или Apache), чтобы изменения вступили в силу. Теперь все запросы, приходящие к этому HTTP-сервису, будут автоматически авторизоваться под указанным пользователем 1С, и явный ввод логина/пароля в браузере или JavaScript не потребуется.

  2. Авторизация через JavaScript с Basic Auth

    Если вам необходимо передавать логин и пароль непосредственно из браузера, мы можем использовать JavaScript и объект fetch (или XMLHttpRequest) для добавления заголовка Authorization. Этот метод позволяет динамически передавать учетные данные, однако он менее безопасен, так как логин и пароль в коде страницы становятся доступны для просмотра (даже если они закодированы в Base64).

    Создадим простую HTML-форму и JS-код, который перехватит событие отправки формы и выполнит POST-запрос с заголовком авторизации.

    
    <!-- Пример HTML формы -->
    <form id="myForm">
        <input type="text" placeholder="Введите текст" name="edit" required autofocus>
        <button type="submit">Сформировать</button>
    </form>
    
    <!-- JavaScript код -->
    <script>
    document.getElementById('myForm').addEventListener('submit', function(event) {
        event.preventDefault(); // Предотвращаем стандартную отправку формы
    
        let url = 'http://ваш_адрес_сервиса_1с/e1cib/http/ваш_сервис';
        let username = 'ЛогинПользователя1С'; // ВНИМАНИЕ: это небезопасно для чувствительных данных
        let password = 'ПарольПользователя1С'; // ВНИМАНИЕ: это небезопасно для чувствительных данных
    
        let formData = new FormData(this); // Получаем данные из формы
        let requestBody = {};
        for (let [key, value] of formData.entries()) {
            requestBody[key] = value;
        }
    
        let headers = new Headers();
        // Формируем заголовок Basic Auth: "Basic " + Base64(логин:пароль)
        headers.append('Authorization', 'Basic ' + btoa(username + ":" + password));
        // Указываем, что отправляем данные в формате JSON (удобнее для 1С)
        headers.append('Content-Type', 'application/json'); 
    
        fetch(url, {
            method: 'POST',
            headers: headers,
            body: JSON.stringify(requestBody) // Отправляем тело запроса как JSON-строку
        })
        .then(response => {
            if (!response.ok) {
                // Если ответ не OK (например, 401 Unauthorized), выбрасываем ошибку
                return response.text().then(text => { throw new Error(text || 'Ошибка HTTP: ' + response.status); });
            }
            console.log('Ответ от 1С получен');
            return response.blob(); // Ожидаем бинарные данные (для Excel)
        })
        .then(blob => {
            // Дальнейшая обработка Blob для скачивания файла будет описана ниже
            handleFileDownload(blob, 'report.xlsx');
        })
        .catch(error => {
            console.error('Ошибка при выполнении запроса:', error);
            alert('Произошла ошибка: ' + error.message);
        });
    });
    
    // Функция handleFileDownload будет описана в разделе про скачивание файла
    function handleFileDownload(blob, filename) {
        // ... реализация ...
    }
    </script>
    

    Важно помнить, что передача логина и пароля в коде клиента не является безопасной практикой для систем, требующих высокой степени защиты. Рассмотрите этот метод только для некритичных систем или в закрытых корпоративных сетях.

  3. Использование PHP-прокси (Наиболее гибкий и безопасный подход)

    Если требуется скрыть учетные данные 1С от клиента, обойти проблемы CORS и обеспечить дополнительный уровень безопасности, рекомендуем использовать PHP-скрипт (или скрипт на любом другом серверном языке) в качестве прокси-сервера. В этом сценарии клиентский HTML/JS будет обращаться к вашему PHP-скрипту, который, в свою очередь, будет отправлять запрос к 1С. Таким образом, учетные данные 1С хранятся только на вашем сервере, а не в браузере клиента.

    Создадим HTML/JS код для обращения к PHP-прокси и сам PHP-скрипт:

    
    <!-- Пример HTML/JS для обращения к PHP прокси -->
    <script>
    document.getElementById('myForm').addEventListener('submit', function(event) {
        event.preventDefault();
        let formData = new FormData(this); // Получаем данные из формы
    
        // Отправляем данные формы к нашему PHP-прокси
        fetch('http://ваш_домен/proxy.php', {
            method: 'POST',
            body: formData // Отправляем как FormData, PHP легко его распарсит
        })
        .then(response => {
            if (!response.ok) {
                return response.text().then(text => { throw new Error(text || 'Ошибка HTTP: ' + response.status); });
            }
            // PHP-прокси должен передать заголовки Content-Type и Content-Disposition от 1С
            const contentDisposition = response.headers.get('Content-Disposition');
            let filename = 'report.xlsx'; // Имя файла по умолчанию
            if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
                const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                const matches = filenameRegex.exec(contentDisposition);
                if (matches != null && matches[1]) {
                    filename = matches[1].replace(/['"]/g, ''); // Извлекаем имя файла из заголовка
                }
            }
            // Возвращаем как Blob вместе с извлеченным именем файла
            return response.blob().then(blob => ({ blob, filename }));
        })
        .then(({ blob, filename }) => {
            handleFileDownload(blob, filename); // Скачиваем файл
        })
        .catch(error => {
            console.error('Ошибка при выполнении запроса через прокси:', error);
            alert('Произошла ошибка: ' + error.message);
        });
    });
    </script>
    
    <!-- proxy.php -->
    <?php
    // Учетные данные 1С (хранить в файле .env или другом защищенном месте!)
    $user1C = 'ЛогинПользователя1С';
    $pass1C = 'ПарольПользователя1С';
    $serviceUrl = 'http://ваш_адрес_сервиса_1с/e1cib/http/ваш_сервис';
    
    // Подготавливаем POST данные из запроса клиента
    // $_POST для данных формы, file_get_contents('php://input') для JSON
    $postData = http_build_query($_POST); 
    
    // Инициализация cURL
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $serviceUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Возвращать результат в переменную
    curl_setopt($ch, CURLOPT_POST, true); // Указываем, что это POST запрос
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); // Тело запроса
    
    // Настраиваем Basic Auth для 1С (это происходит на сервере, не в браузере)
    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    curl_setopt($ch, CURLOPT_USERPWD, $user1C . ":" . $pass1C);
    
    // Получаем заголовки ответа 1С, чтобы передать их обратно клиенту
    curl_setopt($ch, CURLOPT_HEADER, true); 
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Следовать редиректам, если есть
    
    $response = curl_exec($ch);
    
    if (curl_errno($ch)) {
        http_response_code(500);
        echo 'Ошибка cURL: ' . curl_error($ch);
        exit();
    }
    
    // Разделяем заголовки и тело ответа
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $headers = substr($response, 0, $header_size);
    $body = substr($response, $header_size);
    
    // Передаем заголовки от 1С обратно клиенту
    foreach (explode("\r\n", $headers) as $header) {
        // Передаем только нужные заголовки, чтобы не вызывать конфликтов
        if (stripos($header, 'Content-Type:') === 0 || 
            stripos($header, 'Content-Disposition:') === 0 || 
            stripos($header, 'Content-Length:') === 0 ||
            stripos($header, 'ETag:') === 0 ||
            stripos($header, 'Last-Modified:') === 0) {
            header($header, false); // false, чтобы не перезаписывать уже установленные PHP заголовки
        }
    }
                
    // Обязательно устанавливаем заголовок CORS для клиента, если прокси на другом домене
    header("Access-Control-Allow-Origin: *"); 
    header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
    header("Access-Control-Allow-Headers: Content-Type");
    
    echo $body; // Выводим тело ответа 1С
    curl_close($ch);
    ?>
    

    Использование PHP-прокси — это мощный инструмент для обеспечения безопасности и гибкости при интеграции с 1С.

Обработка CORS (Cross-Origin Resource Sharing)

Как мы уже выяснили, если ваша HTML-страница и HTTP-сервис 1С находятся на разных доменах или портах, браузер по умолчанию заблокирует запросы. Это решается добавлением специальных заголовков в ответе HTTP-сервиса 1С. Кроме того, мы должны учитывать предварительный OPTIONS-запрос.

  1. Настройка HTTP-сервиса 1С для обработки CORS

    В вашем модуле HTTP-сервиса 1С необходимо добавить следующие заголовки в объект HTTPСервисОтвет для каждого метода (Post, Get, Options), который может быть вызван из браузера.

    
    // Пример в модуле HTTP-сервиса 1С
    Функция Post(Запрос)
        Ответ = Новый HTTPСервисОтвет(200);
    
        // **Обязательные заголовки CORS для всех методов**
        // Разрешаем запросы со всех доменов (или укажите конкретный домен, например, "http://мойсайт.ru")
        Ответ.УстановитьЗаголовок("Access-Control-Allow-Origin", "*");
        // Разрешаем браузеру отправлять запросы с методами POST, GET, OPTIONS
        Ответ.УстановитьЗаголовок("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        // Разрешаем передачу кастомных заголовков (например, Content-Type, Authorization)
        Ответ.УстановитьЗаголовок("Access-Control-Allow-Headers", "Content-Type, Authorization");
        // Указываем, какие заголовки ответа браузеру разрешено читать (для Content-Disposition)
        Ответ.УстановитьЗаголовок("Access-Control-Expose-Headers", "Content-Disposition"); 
    
        // Если запрос OPTIONS (предварительный запрос CORS)
        Если Запрос.Метод = "OPTIONS" Тогда
            // Для OPTIONS-запроса достаточно вернуть пустой ответ с кодом 200 и CORS-заголовками
            // Браузеру не нужно тело ответа для OPTIONS, только заголовки.
            Возврат Ответ;
        КонецЕсли;
    
        // *** Здесь начинается основной код обработки POST-запроса ***
        // ... Ваш код для обработки запроса и генерации ответа ...
        // ... Например, формирование файла Excel ...
        // *** Конец основного кода ***
    
        Возврат Ответ;
    КонецФункции
    

    Обязательно реализуйте обработку метода OPTIONS. Самый простой способ — это просто вызвать функцию Post (или другую функцию, которая гарантированно устанавливает все необходимые CORS-заголовки) и вернуть ее ответ, так как для OPTIONS-запроса важны только заголовки, а не тело ответа.

    
    // Пример обработки OPTIONS в 1С
    Функция Options(Запрос)
        // Просто вызываем Post, так как она уже содержит логику установки CORS-заголовков.
        // Главное, чтобы для OPTIONS она не пыталась обрабатывать тело запроса.
        Возврат Post(Запрос); 
    КонецФункции
    

    Без корректной настройки CORS, запросы из браузера к 1С будут блокироваться, и вы будете видеть ошибки в консоли разработчика браузера, связанные с нарушением политики безопасности.

Получение и скачивание файла Excel в браузере

После того как HTTP-сервис 1С сгенерировал и отправил Excel-файл, нам нужно заставить браузер его скачать, а не просто получить как абстрактный набор данных.

  1. Настройка HTTP-сервиса 1С для отдачи файла

    В коде 1С при формировании ответа необходимо установить правильные заголовки Content-Type и Content-Disposition. Эти заголовки сообщают браузеру, какой тип данных он получает и как с ними следует поступить (в данном случае, сохранить как файл).

    
    // Пример в модуле HTTP-сервиса 1С
    Функция Post(Запрос)
        Ответ = Новый HTTPСервисОтвет(200);
                    
        // ... Установка CORS-заголовков, как описано выше ...
    
        // Создаем и записываем данные в двоичные данные
        ИмяВременногоФайла = ПолучитьИмяВременногоФайла(".xlsx");
                    
        // Пример: создаем табличный документ и сохраняем его в файл
        ТабДок = Новый ТабличныйДокумент();
        // ... Заполнение ТабДок ...
        ТабДок.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.XLSX);
    
        ДвоичныеДанныеФайлаExcel = Новый ДвоичныеДанные(ИмяВременногоФайла);
        УдалитьФайлы(ИмяВременногоФайла); // Очищаем временный файл
    
        // Устанавливаем тип контента для файла Excel (для .xlsx)
        Ответ.УстановитьЗаголовок("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        // Указываем браузеру, что файл нужно скачать и предлагаем имя
        Ответ.УстановитьЗаголовок("Content-Disposition", "attachment; filename=\"report.xlsx\"");
        // Устанавливаем тело ответа как двоичные данные файла Excel
        Ответ.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеФайлаExcel); 
                    
        Возврат Ответ;
    КонецФункции
    

    Заголовок Content-Disposition: attachment; filename="report.xlsx" является ключевым для инициирования скачивания файла браузером.

  2. JavaScript для скачивания файла

    В клиентском JavaScript, после получения ответа от 1С в виде Blob, используйте специальную функцию для программного создания ссылки и имитации клика по ней. Это позволит браузеру инициировать процесс загрузки.

    
    <script>
    // Эта функция будет вызвана в .then(blob => ...) блоке fetch запроса
    function handleFileDownload(blob, filename) {
        // Создаем временный URL для Blob-объекта
        const url = window.URL.createObjectURL(blob);
                    
        // Создаем невидимый элемент <a>
        const a = document.createElement('a');
        a.style.display = 'none'; // Скрываем элемент
        a.href = url; // Присваиваем временный URL
        a.download = filename; // Указываем имя файла для скачивания
    
        document.body.appendChild(a); // Добавляем элемент в DOM
        a.click(); // Имитируем клик по ссылке, что инициирует загрузку
    
        window.URL.revokeObjectURL(url); // Очищаем временный URL после использования
        a.remove(); // Удаляем временный элемент <a>
    }
    </script>
    

    Эта функция обеспечивает корректное скачивание файла, полученного по HTTP, без перезагрузки страницы или перенаправления пользователя.

Обработка тела POST-запроса в 1С

Разберем, как 1С получает и парсит данные, отправленные из HTML/JavaScript, поскольку способ получения данных зависит от их формата (например, форма или JSON).

  1. Для application/x-www-form-urlencoded (стандартная форма) или multipart/form-data (для файлов)

    Если данные отправляются из стандартной HTML-формы или с помощью объекта FormData в JavaScript без указания Content-Type: application/json, 1С обычно получает их в формате "ключ=значение". Для доступа к этим данным используйте метод Запрос.ПолучитьПараметрыТела().

    
    // Пример в 1С для получения данных из формы
    Функция Post(Запрос)
        // ... Установка CORS-заголовков ...
    
        Если Запрос.Метод = "OPTIONS" Тогда
            Возврат Ответ;
        КонецЕсли;
    
        // Получаем параметры из тела POST-запроса
        ПараметрыТела = Запрос.ПолучитьПараметрыТела();
        Если ПараметрыТела.Свойство("edit") Тогда
            ЗначениеПоля = ПараметрыТела.edit; // Получаем значение поля с именем 'edit'
            Сообщить("Получено значение из формы: " + ЗначениеПоля);
            // ... дальнейшая логика ...
        КонецЕсли;
                    
        Возврат Новый HTTPСервисОтвет(200);
    КонецФункции
    
  2. Для application/json (при отправке через fetch с JSON.stringify)

    Если вы отправляете данные из JavaScript в формате JSON (как в примере с fetch выше, где мы использовали JSON.stringify(requestBody) и заголовок Content-Type: application/json), то в 1С эти данные придут как обычная строка. Для их десериализации используйте метод Запрос.ПолучитьТелоКакСтроку(), а затем объект JSON для парсинга.

    
    // Пример в 1С для получения данных в формате JSON
    Функция Post(Запрос)
        // ... Установка CORS-заголовков ...
    
        Если Запрос.Метод = "OPTIONS" Тогда
            Возврат Ответ;
        КонецЕсли;
                    
        // Получаем тело запроса как строку
        СтрокаJSON = Запрос.ПолучитьТелоКакСтроку();
                    
        // Проверяем, что строка не пустая, прежде чем пытаться парсить
        Если Не ПустаяСтрока(СтрокаJSON) Тогда
            Попытка
                ЧтениеJSON = Новый ЧтениеJSON();
                ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
                ДанныеИзJSON = JSON.Прочитать(ЧтениеJSON); // Десериализуем JSON-строку
                ЧтениеJSON.Закрыть();
    
                Если ДанныеИзJSON.Свойство("edit") Тогда
                    ЗначениеПоля = ДанныеИзJSON.edit;
                    Сообщить("Получено значение из JSON: " + ЗначениеПоля);
                    // ... дальнейшая логика ...
                КонецЕсли;
            Исключение
                Сообщить("Ошибка при парсинге JSON: " + ОписаниеОшибки());
                Возврат Новый HTTPСервисОтвет(400); // Bad Request
            КонецПопытки;
        Иначе
            Сообщить("Тело запроса в формате JSON пустое.");
        КонецЕсли;
    
        Возврат Новый HTTPСервисОтвет(200);
    КонецФункции
    

    Используйте Попытка...Исключение при парсинге JSON, так как клиент может отправить некорректные данные, что приведет к ошибке.

Использование лицензий и оптимизация

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

  1. Настройка времени жизни сеанса

    Для оптимизации использования лицензий рекомендуется настроить параметр sessionMaxAge в файле публикации вашего HTTP-сервиса (default.vrd или ваш_сервис.vrd). Этот параметр определяет максимальное время (в секундах), в течение которого сеанс 1С будет оставаться активным после последнего обращения к нему.

    Добавьте или измените параметр <v8:sessionMaxAge> внутри тега <v8:point>:

    
    <?xml version="1.0" encoding="UTF-8"?>
    <v8:point xmlns:v8="http://v8.1c.ru/8.3/data/point">
        <v8:base ref="имя_вашей_базы" alias="имя_вашей_базы"/>
        <v8:userName>ИмяПользователя1С</v8:userName>
        <v8:app name="e1cib/http/ваш_сервис" connectionString="Srvr="ИмяСервера1С";Ref="ИмяБазы1С";"/>
        <v8:sessionMaxAge>300</v8:sessionMaxAge> <!-- Сеанс будет жить 300 секунд (5 минут) -->
    </v8:point>
    

    Оптимальное значение sessionMaxAge зависит от интенсивности использования вашего HTTP-сервиса. Слишком маленькое значение может привести к частому созданию новых сеансов, что увеличивает нагрузку на сервер. Слишком большое — к неоправданному удержанию лицензий.

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

← На главную