В рамках данной статьи мы подробно рассмотрим процесс интеграции HTML-страницы с HTTP-сервисом 1С, охватывая вопросы отправки POST-запросов, методов авторизации и эффективного получения файлов Excel. Мы выясним, как преодолеть типичные сложности, такие как CORS, и обеспечим корректное взаимодействие между клиентской частью и серверной логикой 1С.
Прежде чем погрузиться в решения, разберем, с какими проблемами чаще всего сталкивается разработчик при попытке отправить POST-запрос напрямую из HTML-формы или с использованием JavaScript в сторону HTTP-сервиса 1С.
fetch или XMLHttpRequest). Требуется дополнительная логика на стороне клиента для инициирования загрузки.mywebsite.com), а HTTP-сервис 1С доступен на другом домене (или даже на другом порту того же IP-адреса), браузер по умолчанию заблокирует междоменный запрос. Это распространенная проблема, которую необходимо решать на стороне HTTP-сервиса 1С.application/x-www-form-urlencoded, multipart/form-data или text/plain) сначала отправляют предварительный запрос методом OPTIONS. Если ваш HTTP-сервис в 1С не умеет обрабатывать этот метод и не возвращает пустой ответ с кодом 200 и нужными CORS-заголовками, основной POST-запрос даже не будет отправлен.Рассмотрим несколько подходов для прохождения авторизации при обращении к HTTP-сервису 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 не потребуется.
Если вам необходимо передавать логин и пароль непосредственно из браузера, мы можем использовать 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>
Важно помнить, что передача логина и пароля в коде клиента не является безопасной практикой для систем, требующих высокой степени защиты. Рассмотрите этот метод только для некритичных систем или в закрытых корпоративных сетях.
Если требуется скрыть учетные данные 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С.
Как мы уже выяснили, если ваша HTML-страница и HTTP-сервис 1С находятся на разных доменах или портах, браузер по умолчанию заблокирует запросы. Это решается добавлением специальных заголовков в ответе HTTP-сервиса 1С. Кроме того, мы должны учитывать предварительный OPTIONS-запрос.
В вашем модуле 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С будут блокироваться, и вы будете видеть ошибки в консоли разработчика браузера, связанные с нарушением политики безопасности.
После того как HTTP-сервис 1С сгенерировал и отправил Excel-файл, нам нужно заставить браузер его скачать, а не просто получить как абстрактный набор данных.
В коде 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" является ключевым для инициирования скачивания файла браузером.
В клиентском 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, без перезагрузки страницы или перенаправления пользователя.
Разберем, как 1С получает и парсит данные, отправленные из HTML/JavaScript, поскольку способ получения данных зависит от их формата (например, форма или JSON).
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);
КонецФункции
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С) потребляет клиентскую лицензию. При большом количестве запросов или долгих сеансах лицензии могут быстро закончиться.
Для оптимизации использования лицензий рекомендуется настроить параметр 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С, создавая гибкие и функциональные решения.