При интеграции 1С с внешними API и платежными шлюзами разработчики часто сталкиваются с ситуацией, когда отправленный HTTP-запрос не приносит желаемого результата. Вроде бы код написан по шаблону, но сервер возвращает пустой ответ, ошибку авторизации Authorization has been denied for this request или странное сообщение о перенаправлении 302 Object Moved.
В этой статье мы подробно разберем типичные ошибки, которые совершают программисты 1С при работе с объектами HTTPСоединение и HTTPЗапрос. Мы пошагово проанализируем каждую проблему на примере реального кейса интеграции с платежным сервисом «Экспресс Платежи» (api.express-pay.by) и соберем идеальный рабочий шаблон кода для отправки POST-запросов.
---
Для начала проанализируем исходный код, который часто приводит к сбоям, и выделим в нем критические уязвимости. Обычно разработчики пытаются уместить весь URL-адрес в одно место или забывают про особенности работы протокола HTTPS в 1С. Рассмотрим основные проблемы по очереди.
Взглянем на частую ошибку инициализации объектов работы с сетью:
// Ошибочный вариант
HTTPСоединение = Новый HTTPСоединение("https://api.express-pay.by/v1/invoices?token={Token}");
запросPOST = Новый HTTPЗапрос("api.express-pay.by");
При создании HTTPСоединение в качестве первого параметра должен передаваться исключительно адрес сервера (хост) без указания протокола (http/https), портов и путей. Все, что идет после имени домена (включая параметры запроса), должно передаваться в объекте HTTPЗапрос.
Если написать так, как в примере выше, то 1С попытается обратиться к несуществующему хосту. Правильное разделение выглядит следующим образом:
api.express-pay.by/v1/invoicesЕсли мы создаем объект HTTPСоединение простым конструктором:
HTTPСоединение = Новый HTTPСоединение("api.express-pay.by");
то 1С по умолчанию пытается установить связь по незащищенному протоколу HTTP (порт 80). Современные веб-серверы и платежные шлюзы в целях безопасности запрещают незащищенные соединения. В ответ на такой запрос сервер присылает HTTP-статус 302 Found (или Object Moved) и перенаправляет клиентское приложение на защищенную версию адреса с HTTPS.
В файле ответа при этом можно увидеть HTML-код с текстом: This document may be found here. Чтобы избежать нежелательного перенаправления, необходимо сразу инициализировать защищенное соединение SSL, передав в конструктор порт 443 и объект ЗащищенноеСоединениеOpenSSL.
В документации к различным API параметры часто обозначают в фигурных скобках, например: /v1/invoices?token={token}. Это лишь плейсхолдер, указывающий на то, что вместо {token} нужно подставить реальное строковое значение ключа безопасности.
Если разработчик буквально переносит фигурные скобки в код 1С:
запросPOST = Новый HTTPЗапрос("/v1/invoices?token={" + Token + "}");
то сервер принимает эти скобки как часть токена (в закодированном виде они превращаются в символы %7B и %7D). Естественно, валидация ключа на стороне сервера проваливается, и система возвращает ошибку авторизации: {"Message":"Authorization has been denied for this request."}. Фигурные скобки необходимо убирать.
При отправке данных формы методом POST с типом контента application/x-www-form-urlencoded все передаваемые параметры склеиваются в одну строку. Параметры должны разделяться строго символом амперсанда &, а не системными разделителями строк 1С (такими как Символы.ПС).
Более того, любые спецсимволы, кириллица или пробелы в значениях параметров (например, в назначении платежа или имени клиента) должны быть корректно закодированы. В противном случае веб-сервер не сможет корректно распарсить тело запроса.
---
Теперь, когда мы проанализировали причины основных ошибок, разработаем надежный и гибкий алгоритм отправки POST-запроса в 1С. Мы откажемся от записи ответов во временные файлы на диске (чтобы не зависеть от прав доступа в операционной системе) и научимся обрабатывать ответы сервера прямо в оперативной памяти.
Для начала подготовим строку параметров для передачи в теле POST-запроса. Все параметры должны быть приведены к формату URL-строки. Для этого мы напишем вспомогательную функцию кодирования параметров, чтобы гарантировать корректность отправляемых данных.
// Функция для безопасного кодирования параметров запроса
Функция КодироватьПараметр(ЗначениеПараметра)
Возврат КодироватьСтроку(Строка(ЗначениеПараметра), СпособКодированияСтроки.КодировкаURL);
КонецФункции
Теперь соберем саму строку параметров, разделяя их знаком &:
// Формируем параметры тела запроса (токен в теле дублировать не нужно, если он передается в URL)
ПараметрыТела = "AccountNo=" + КодироватьПараметр("123456")
+ "&Amount=" + КодироватьПараметр("150.00")
+ "&Currency=" + КодироватьПараметр("933") // 933 - код белорусского рубля BYN
+ "&Info=" + КодироватьПараметр("Оплата за ИТ-услуги")
+ "&ReturnInvoiceUrl=1";
Для отправки запроса на защищенный хост нам обязательно потребуется объект ЗащищенноеСоединениеOpenSSL. Создадим его с дефолтными системными настройками сертификатов. Это гарантирует беспрепятственную работу с протоколом HTTPS.
// Определяем параметры подключения к серверу
СерверИсточник = "api.express-pay.by";
ПортПодключения = 443; // Стандартный порт для HTTPS
// Инициализируем защищенное SSL-соединение
Защита = Новый ЗащищенноеСоединениеOpenSSL();
HTTPСоединение = Новый HTTPСоединение(СерверИсточник, ПортПодключения, , , , , Защита);
Создаем объект HTTPЗапрос. В качестве параметра конструктора передаем только путь к ресурсу на сервере и параметры строки запроса (в нашем случае — токен авторизации). Также обязательно устанавливаем заголовок Content-Type, сообщающий серверу, в каком формате передаются данные в теле POST-запроса.
// Путь к ресурсу API с корректным подставлением токена авторизации (БЕЗ фигурных скобок!)
ТокенАвторизации = "ваш_секретный_токен_из_личного_кабинета";
ПутьКРесурсу = "/v1/invoices?token=" + ТокенАвторизации;
// Инициализируем запрос
ЗапросPOST = Новый HTTPЗапрос(ПутьКРесурсу);
// Устанавливаем обязательный заголовок для передачи параметров формы
ЗапросPOST.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
// Заполняем тело запроса нашей закодированной строкой параметров в кодировке UTF-8
ЗапросPOST.УстановитьТелоИзСтроки(ПараметрыТела, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Вместо того чтобы записывать результаты во внешние файлы (например, на диск C:\, к которому у сервера 1С может просто не быть прав доступа), мы отправим запрос и получим объект HTTPОтвет. Это позволит нам проанализировать код состояния ответа (например, 200 или 201 для успешных запросов) и прочитать тело ответа напрямую.
Попытка
// Отправляем POST-запрос на обработку
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(ЗапросPOST);
// Получаем код состояния HTTP-ответа
КодСостояния = HTTPОтвет.КодСостояния;
// Считываем тело ответа сервера как текстовую строку
ТекстОтвета = HTTPОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
// Анализируем результат работы
Если КодСостояния = 200 Или КодСостояния = 201 Тогда
// Запрос успешно обработан сервером
Сообщить("Счет успешно выставлен!");
Сообщить("Ответ сервера: " + ТекстОтвета);
// Здесь можно распарсить полученный JSON ответ, используя объект "ЧтениеJSON"
Иначе
// Сервер вернул ошибку (например, 400, 401, 403, 500)
Сообщить("Ошибка при выставлении счета! Код состояния сервера: " + КодСостояния);
Сообщить("Детали ошибки: " + ТекстОтвета);
КонецЕсли;
Исключение
// Обрабатываем сетевые ошибки (отсутствие связи, неверный домен и т.д.)
ЗаписьЖурналаРегистрации("ИнтеграцияAPI", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
Сообщить("Не удалось установить соединение с сервером. Подробности см. в Журнале регистрации.");
КонецПопытки;
---
Если даже при абсолютно верном и корректном коде 1С вы продолжаете получать ошибку авторизации Authorization has been denied, обязательно проверьте административные настройки на стороне самого сервиса интеграции:
signature будут отклоняться сервером.933. Использование устаревших кодов (например, 974 для старого белорусского рубля) приведет к ошибке валидации формы на стороне платежного шлюза.Применяя предложенный нами структурированный подход к разделению адресного пространства, обязательному включению SSL/HTTPS, URL-кодированию параметров и чтению ответов в оперативную память, вы навсегда избавитесь от неожиданных ошибок обмена данными по HTTP протоколу в среде 1С:Предприятие.