При интеграции 1С с онлайн-кассами АТОЛ через встроенный веб-сервер (входит в состав ДТО 10) разработчики часто сталкиваются с аппаратными и программными ошибками подключения. Одна из самых распространенных ошибок происходит при вызове метода ОтправитьДляОбработки объекта HTTPСоединение, когда платформа возвращает неинформативное системное сообщение: "Ошибка при вызове метода контекста (ОтправитьДляОбработки)".
В этой статье мы подробно разберем, почему возникает эта проблема, как правильно настроить параметры подключения, приведем готовый рабочий код для работы с API веб-сервера АТОЛ и рассмотрим критически важные нюансы, которые необходимо учесть для стабильной работы системы в продакшене.
Проанализируем исходный код, который вызвал ошибку у автора темы:
Соединение = Новый HTTPСоединение("http://127.0.0.1:16732/");
ОтветHTTP = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
В данном фрагменте допущена классическая ошибка проектирования сетевых запросов в 1С. Конструктор объекта HTTPСоединение устроен строго определенным образом. Первый параметр Сервер должен содержать исключительно имя хоста или его IP-адрес. В него нельзя передавать:
http:// или https://);:16732);Если нарушить это правило, платформа 1С не сможет корректно разрешить адрес сервера, из-за чего последующий вызов методов отправки запросов (таких как ОтправитьДляОбработки, Получить или ВызватьHTTPМетод) завершится аварийно.
Для исправления этой ситуации порт необходимо передавать вторым отдельным числовым параметром конструктора, а адрес указывать в "чистом" виде.
// Неправильно:
Соединение = Новый HTTPСоединение("http://127.0.0.1:16732/");
// Правильно:
Адрес = "127.0.0.1";
Порт = 16732;
Соединение = Новый HTTPСоединение(Адрес, Порт);
Рассмотрим правильный и структурированный пример реализации отправки запроса к веб-серверу АТОЛ по современному стандарту API v2. Этот стандарт подразумевает асинхронную работу: мы отправляем задание в очередь, получаем уникальный идентификатор задачи, а затем опрашиваем сервер для получения результата.
Ниже представлен детальный и готовый к использованию код:
// Шаг 1. Инициализируем параметры подключения к веб-серверу
Адрес = "127.0.0.1";
Порт = 16732;
// Обратите внимание на использование параметра защищенного соединения (Ложь для HTTP)
HTTPСоединение = Новый HTTPСоединение(Адрес, Порт, , , , , , Ложь);
// Шаг 2. Формируем HTTP-запрос
// Для отправки заданий в очередь веб-сервера АТОЛ используется ресурс "requests"
HTTPЗапрос = Новый HTTPЗапрос("requests");
HTTPЗапрос.Заголовки.Вставить("Content-type", "application/json");
// Шаг 3. Формируем тело запроса в формате JSON
UUIDЗадания = Новый УникальныйИдентификатор;
СтрокаUUID = Строка(UUIDЗадания);
СтруктураЗапроса = Новый Структура;
СтруктураЗапроса.Вставить("uuid", СтрокаUUID);
// Создаем массив команд для кассы
МассивКоманд = Новый Массив;
Команда = Новый Структура;
Команда.Вставить("type", "getDeviceInfo"); // Команда запроса информации о ККТ
МассивКоманд.Добавить(Команда);
СтруктураЗапроса.Вставить("request", МассивКоманд);
// Сериализуем структуру в JSON-строку
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураЗапроса);
СтрокаJSON = ЗаписьJSON.Закрыть();
// Устанавливаем тело запроса в кодировке UTF-8 без BOM
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
// Шаг 4. Отправляем запрос на веб-сервер
Попытка
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Исключение
ВызватьИсключение "Не удалось связаться с веб-сервером ККТ: " + ОписаниеОшибки();
КонецПопытки;
После отправки запроса веб-сервер возвращает статус 201 Created, подтверждающий успешное добавление задачи в очередь. Теперь система должна узнать статус выполнения команды. В исходном коде на форуме предлагается простой цикл ожидания:
Пока СтатусОперации <> "ready" Цикл
// Запрос статуса...
КонецЦикла;
Внимание! Использовать такой бесконечный цикл без ограничений и задержек в рабочих базах категорически запрещено по следующим причинам:
ready. Сеанс 1С пользователя зависнет навсегда.Посмотрим на пример правильной и безопасной реализации цикла опроса с ограничением по количеству итераций и искусственной паузой:
Если HTTPОтвет.КодСостояния = 201 Тогда
МаксимальноеЧислоПопыток = 30; // Ограничиваем время ожидания ~30 секундами
ТекущаяПопытка = 0;
СтатусОперации = "";
СтруктураРезультата = Неопределено;
Пока СтатусОперации <> "ready" И ТекущаяПопытка < МаксимальноеЧислоПопыток Цикл
ТекущаяПопытка = ТекущаяПопытка + 1;
// Делаем обязательную технологическую паузу в 1 секунду
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Тогда
Приостановить(1); // Доступно на сервере начиная с платформы 8.3.15
#Иначе
// На клиенте в управляемых формах рекомендуется использовать ПодключитьОбработчикОжидания
#КонецЕсли
// Запрашиваем состояние задачи по ее UUID
HTTPЗапросСтатуса = Новый HTTPЗапрос("requests/" + СтрокаUUID);
ОтветСтатуса = HTTPСоединение.Получить(HTTPЗапросСтатуса);
Если ОтветСтатуса.КодСостояния = 200 Тогда
СтрокаОтвета = ОтветСтатуса.ПолучитьТелоКакСтроку();
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаОтвета);
СтруктураРезультата = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Получаем текущий статус задачи из первого элемента массива результатов
Если СтруктураРезультата.Свойство("results") И СтруктураРезультата.results.Количество() > 0 Тогда
СтатусОперации = СтруктураРезультата.results[0].status;
// Если произошла аппаратная или программная ошибка кассы
Если СтатусОперации = "error" Тогда
ВызватьИсключение "Ошибка ККТ: " + СтруктураРезультата.results[0].errorDescription;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Проверяем, вышли ли мы из цикла по таймауту
Если СтатусОперации <> "ready" Тогда
ВызватьИсключение "Превышено время ожидания ответа от онлайн-кассы.";
КонецЕсли;
// Обрабатываем успешный результат
ДанныеУстройства = СтруктураРезультата.results[0].result.deviceInfo;
Сообщить("Связь установлена. Версия конфигурации ККТ: " + ДанныеУстройства.configurationVersion);
КонецЕсли;
Для стабильного функционирования веб-сервера АТОЛ и исключения неочевидных ошибок при промышленной эксплуатации крайне важно соблюдать следующие системные требования:
atol-fptr-web-server-users.exe (находится в каталоге установки драйвера KKT/web) и передавать имя пользователя и пароль в конструктор соединения:
HTTPСоединение = Новый HTTPСоединение(Адрес, Порт, ИмяПользователя, Пароль, , , , Ложь);
deviceCode. Настроить символьные коды для каждого подключенного устройства можно через веб-интерфейс управления сервером АТОЛ по адресу http://127.0.0.1:16732/.Соблюдение этих несложных правил и правильная структура кода инициализации HTTPСоединение позволят вам построить надежную и быструю систему взаимодействия между 1С и кассовым оборудованием.