Вызов внешнего HTTP-сервиса из кода 1С: соединение, запрос, разбор ответа

· 9 мин

Содержание

Нужно забрать курс валюты, отправить заказ в интернет-магазин или проверить контрагента через внешний API. Чтобы 1С обратилась к веб-сервису, создайте объект HTTPСоединение с адресом сервера, соберите HTTPЗапрос с путём и заголовками, вызовите метод соединения (Получить, ОтправитьДляОбработки и другие) и прочитайте HTTPОтвет: код состояния и тело.

Всё это работает в платформе 8.3 без внешних компонент. Дальше разберём каждый шаг на коде, который можно взять за основу. Примеры написаны для обычных управляемых форм и серверных модулей.

С чего начать: что нужно знать о сервисе до написания кода

Прежде чем открывать Конфигуратор, возьмите у разработчика сервиса (или из его документации) пять вещей:

  • 🌐 адрес: протокол, хост, порт и путь, например https://api.example.com/v1/orders;
  • 🔧 метод: GET, POST, PUT, PATCH или DELETE;
  • 📨 формат тела запроса и ответа: чаще всего JSON, реже XML;
  • 🔑 способ авторизации: логин и пароль, токен в заголовке, ключ в адресе, сертификат;
  • ⏱ ограничения: сколько запросов в минуту допускается и какие коды ошибок возвращает сервис.

Проверьте запрос до 1С. Отправьте его из Postman или утилитой curl: если там ответ не приходит, то код 1С не поможет, и вы потратите время на поиск ошибки не там.

Вызывайте сервис на сервере, а не на клиенте. Серверный вызов не зависит от компьютера пользователя, не упирается в его прокси и позволяет делать обмен регламентным заданием.

Создание HTTP-соединения

Соединение хранит адрес сервера, порт, учётные данные и параметры безопасности. Создаётся оно один раз на серию запросов.

Соединение = Новый HTTPСоединение(
    "api.example.com",                    // хост без протокола
    443,                                  // порт
    ,                                     // пользователь
    ,                                     // пароль
    ,                                     // прокси
    30,                                   // таймаут в секундах
    Новый ЗащищенноеСоединениеOpenSSL);   // HTTPS

Разберём параметры конструктора по порядку:

ПараметрЧто передаватьТипичная ошибка
ХостТолько имя сервера: api.example.comПисать https:// внутри имени хоста
Порт443 для HTTPS, 80 для HTTPОставить 80 и стучаться на HTTPS
Пользователь, парольДля Basic-авторизацииПередавать, когда сервис ждёт токен
ПроксиОбъект ИнтернетПроксиЗабыть прокси в корпоративной сети
ТаймаутСекунды ожидания ответаНе задать и зависнуть на минуты
Защищённое соединениеОбъект ЗащищенноеСоединениеOpenSSLНе указать для HTTPS

Если адрес в настройках вам дают целиком, разберите его на части: протокол определит порт и защищённость, а то, что идёт после хоста, пойдёт в запрос.

Прокси и сертификаты

В корпоративной сети без прокси соединение часто просто не устанавливается. Создайте объект ИнтернетПрокси, заполните адрес и порт и передайте его в конструктор соединения.

Сервис с самоподписанным или внутренним сертификатом платформа не примет молча: нужно передать корневой сертификат удостоверяющего центра. Конструктор ЗащищенноеСоединениеOpenSSL принимает клиентский сертификат и сертификаты УЦ. Отключать проверку сертификата, чтобы «заработало», нельзя — вы лишаетесь защиты от подмены сервера.

Формирование и отправка запроса

Запрос — отдельный объект HTTPЗапрос. Ему задают адрес ресурса (то, что идёт после хоста), заголовки и тело.

Запрос GET

Запрос = Новый HTTPЗапрос("/v1/orders?status=new&limit=50");
Запрос.Заголовки.Вставить("Accept", "application/json");

Ответ = Соединение.Получить(Запрос);

Параметры GET идут прямо в адресе. Если в значении есть пробелы, кириллица или спецсимволы, закодируйте их функцией КодироватьСтроку со способом СпособКодированияСтроки.КодировкаURL. Иначе сервис получит искажённый адрес.

Запрос POST с телом JSON

Данные = Новый Структура;
Данные.Вставить("number", "ЗК-000125");
Данные.Вставить("amount", 15400.50);
Данные.Вставить("customer", "ООО Ромашка");

Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, Данные);
ТелоЗапроса = Запись.Закрыть();

Запрос = Новый HTTPЗапрос("/v1/orders");
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

Ответ = Соединение.ОтправитьДляОбработки(Запрос);

Здесь два места, где чаще всего спотыкаются:

  1. Заголовок Content-Type должен совпадать с реальным форматом тела. Сервис, который ждёт JSON, на запрос без заголовка нередко отвечает кодом 415 или 400.
  2. Тело нужно записать без BOM. Многие сервисы не принимают три лишних байта в начале и отвечают ошибкой разбора, хотя по виду тело нормальное.

Остальные методы

Что нужноМетод соединения
Получить данные (GET)Получить
Создать или отправить на обработку (POST)ОтправитьДляОбработки
Заменить ресурс целиком (PUT)Записать
Изменить часть (PATCH)Изменить
Удалить (DELETE)Удалить

Если нужного метода нет в вашем релизе платформы, посмотрите справку по HTTPСоединение — там перечислен полный набор для вашей версии.

Авторизация: как передать логин, пароль и токен

Способ зависит от сервиса. Вот три самых частых варианта.

Basic. Логин и пароль можно передать прямо в конструктор соединения (третий и четвёртый параметры). Платформа сама сформирует заголовок.

Токен в заголовке. Самый распространённый вариант для современных API:

Запрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);

Ключ в адресе или в своём заголовке. Название заголовка (X-API-Key и подобные) каждый сервис задаёт сам — смотрите его документацию.

Токены часто живут от часа до суток. Сервис вернёт 401, когда срок истечёт, — тогда запросите новый токен и повторите вызов один раз, а не в бесконечном цикле.

Где хранить секреты

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

Не пишите токен в текст сообщения об ошибке и не складывайте заголовки запроса в журнал целиком. Через них пароль уходит в логи.

Обработка ответа: код состояния, заголовки, тело

После вызова проверьте код, и только потом читайте тело.

Если Ответ.КодСостояния = 200 Тогда
    ТекстОтвета = Ответ.ПолучитьТелоКакСтроку("UTF-8");

    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(ТекстОтвета);
    Результат = ПрочитатьJSON(Чтение, Истина);
    Чтение.Закрыть();

    Для Каждого Элемент Из Результат["items"] Цикл
        Сообщить(Элемент["number"] + ": " + Элемент["status"]);
    КонецЦикла;
Иначе
    ВызватьИсключение СтрШаблон("Сервис вернул код %1: %2",
        Ответ.КодСостояния, Ответ.ПолучитьТелоКакСтроку("UTF-8"));
КонецЕсли;

Второй параметр Истина в ПрочитатьJSON возвращает объекты JSON как соответствие, а массивы — как массив. К полям обращаются по ключу в квадратных скобках, как в примере. Без этого параметра получите структуру, и ключи с недопустимыми для имени символами (дефис, пробел) вызовут ошибку.

Как понимать коды ответа

КодЧто значитЧто делать
200Успех, данные в телеЧитать тело
201Ресурс созданВзять идентификатор из тела или заголовка Location
204Успех, тела нетНе пытаться разбирать JSON
400Сервис не понял запросПроверить тело и обязательные поля
401Нет или просрочена авторизацияОбновить токен, проверить пароль
403Доступ запрещёнВыдать права учётной записи сервиса
404Адрес не найденПроверить путь и версию API
429Слишком много запросовПодождать и повторить
500 и вышеСбой на стороне сервисаПовторить позже, записать в журнал

Разбор XML и сжатый ответ

Если сервис отвечает XML, читайте тело объектом ЧтениеXML: загрузите строку методом УстановитьСтроку и обходите узлы методом Прочитать. Для крупных документов быстрее, чем держать всё в памяти. Для SOAP-сервисов с WSDL используйте WSОпределения и WSПрокси: платформа сама подготовит вызов операций по описанию.

Ответ, пришедший в сжатом виде, платформа обычно распаковывает сама. Но если кириллица в теле превратилась в набор символов вроде Ð, значит, вы читаете тело в чужой кодировке — передайте нужную кодировку в ПолучитьТелоКакСтроку.

Ошибки и непредвиденные ситуации

Сеть ненадёжна: сервис может не ответить, оборвать соединение или вернуть мусор. Оберните вызов в Попытка … Исключение, а в блоке Исключение берите текст через ОписаниеОшибки().

Попытка
    Ответ = Соединение.Получить(Запрос);
Исключение
    ЗаписьЖурналаРегистрации("ИнтеграцияСервис",
        УровеньЖурналаРегистрации.Ошибка, , ,
        ОписаниеОшибки());
    Возврат Неопределено;
КонецПопытки;

Что нужно предусмотреть:

  • ⏱ Таймаут. Без него поток ждёт ответа до срока по умолчанию. Для справочных запросов хватает 10–30 секунд, для тяжёлых выгрузок ставьте больше и запускайте в фоновом задании.
  • 🔁 Повторы. При 429 и кодах 5xx повторите запрос 2–3 раза с нарастающей паузой (например, 1, 3 и 10 секунд). Повторять 400 и 404 бессмысленно.
  • 📝 Журнал. Пишите адрес, код ответа и время. Тело с персональными данными и токены в журнал не кладите.
  • 🧱 Идемпотентность. Если POST создаёт документ на стороне сервиса, повтор после таймаута может создать дубль. Узнайте, поддерживает ли сервис ключ идемпотентности, или сначала проверьте, не создан ли объект.
Диагностика: выберите симптом

Практические приёмы: как сделать вызов надёжным

Когда обращений к сервису больше одного, выносите их в отдельную общую функцию. Хватит одной процедуры, которая принимает метод, путь и тело, а возвращает код и разобранный ответ. Тогда авторизация, таймаут, журнал и повторы живут в одном месте, а не в десяти.

Что ещё помогает на практике:

  • 📦 Адрес сервиса и токен храните в настройках, а не в коде. Сменился адрес — меняете значение, а не конфигурацию.
  • 🧪 Тестовый контур. Если у сервиса есть песочница, держите в настройках переключатель между боевым и тестовым адресом.
  • ⏰ Регламентное задание. Периодический обмен (курсы, статусы заказов) запускайте регламентным заданием, а не по кнопке пользователя.
  • 📄 Постраничная выгрузка. Сервисы редко отдают всё сразу: читайте параметры вроде limit и offset или признак следующей страницы и запрашивайте в цикле.
  • 🔍 Отладка. Чтобы увидеть, что реально уходит в сеть, пропустите трафик через отладочный прокси на тестовом сервере. По журналу 1С этого не видно.

Какие типы ответов бывают

Не каждый сервис возвращает JSON. Бывает, что приходит файл или двоичные данные: тогда используйте ПолучитьТелоКакДвоичныеДанные и сохраняйте результат в файл или во временное хранилище, а не пытайтесь читать как строку.

Для отправки файла в теле запроса применяйте УстановитьТелоИзДвоичныхДанных и выставьте Content-Type, который ждёт сервис. Для формы с файлом (multipart/form-data) тело придётся собрать вручную, с границей между частями, — готового объекта для этого в платформе нет.

Частые вопросы

Можно ли вызвать веб-сервис с клиента, а не с сервера?
Технически объекты HTTP доступны и на клиенте, но на тонком и веб-клиенте это упирается в сеть пользователя и ограничения браузера. Для регулярных обменов используйте серверный вызов.
Чем HTTP-сервис отличается от веб-сервиса в 1С?
В 1С есть два понятия: ваша база может сама публиковать HTTP-сервисы и веб-сервисы (SOAP) для внешних систем, а в этой теме 1С выступает клиентом и обращается к чужому сервису.
Что делать, если сервис требует SOAP, а не JSON?
Подключите описание через WSОпределения, создайте WSПрокси и вызывайте операции как методы. Тело и конверт платформа соберёт сама.
Как передать запрос с кириллицей в адресе?
Закодируйте значение параметра функцией КодироватьСтроку в режиме КодировкаURL. Не кодируйте весь адрес целиком — сломаются символы /, ? и &.
Сколько запросов можно отправлять подряд?
Лимит задаёт сам сервис, обычно в его документации. При превышении он вернёт 429; разделите запросы паузами и не запускайте параллельно сотни заданий.