Вызов внешнего HTTP-сервиса из кода 1С: соединение, запрос, разбор ответа
Содержание
Нужно забрать курс валюты, отправить заказ в интернет-магазин или проверить контрагента через внешний 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.НеИспользовать);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Здесь два места, где чаще всего спотыкаются:
- Заголовок
Content-Typeдолжен совпадать с реальным форматом тела. Сервис, который ждёт JSON, на запрос без заголовка нередко отвечает кодом 415 или 400. - Тело нужно записать без 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 создаёт документ на стороне сервиса, повтор после таймаута может создать дубль. Узнайте, поддерживает ли сервис ключ идемпотентности, или сначала проверьте, не создан ли объект.
ЗащищенноеСоединениеOpenSSL или установите его в хранилище сервера. Проверку не отключайте.Content-Type, отсутствие BOM в теле и названия полей: регистр в JSON имеет значение.Bearer, если сервис его требует, и что он не просрочен.Content-Type.Практические приёмы: как сделать вызов надёжным
Когда обращений к сервису больше одного, выносите их в отдельную общую функцию. Хватит одной процедуры, которая принимает метод, путь и тело, а возвращает код и разобранный ответ. Тогда авторизация, таймаут, журнал и повторы живут в одном месте, а не в десяти.
Что ещё помогает на практике:
- 📦 Адрес сервиса и токен храните в настройках, а не в коде. Сменился адрес — меняете значение, а не конфигурацию.
- 🧪 Тестовый контур. Если у сервиса есть песочница, держите в настройках переключатель между боевым и тестовым адресом.
- ⏰ Регламентное задание. Периодический обмен (курсы, статусы заказов) запускайте регламентным заданием, а не по кнопке пользователя.
- 📄 Постраничная выгрузка. Сервисы редко отдают всё сразу: читайте параметры вроде
limitиoffsetили признак следующей страницы и запрашивайте в цикле. - 🔍 Отладка. Чтобы увидеть, что реально уходит в сеть, пропустите трафик через отладочный прокси на тестовом сервере. По журналу 1С этого не видно.
Какие типы ответов бывают
Не каждый сервис возвращает JSON. Бывает, что приходит файл или двоичные данные: тогда используйте ПолучитьТелоКакДвоичныеДанные и сохраняйте результат в файл или во временное хранилище, а не пытайтесь читать как строку.
Для отправки файла в теле запроса применяйте УстановитьТелоИзДвоичныхДанных и выставьте Content-Type, который ждёт сервис. Для формы с файлом (multipart/form-data) тело придётся собрать вручную, с границей между частями, — готового объекта для этого в платформе нет.
Частые вопросы
Можно ли вызвать веб-сервис с клиента, а не с сервера?
Чем HTTP-сервис отличается от веб-сервиса в 1С?
Что делать, если сервис требует SOAP, а не JSON?
WSОпределения, создайте WSПрокси и вызывайте операции как методы. Тело и конверт платформа соберёт сама.Как передать запрос с кириллицей в адресе?
КодироватьСтроку в режиме КодировкаURL. Не кодируйте весь адрес целиком — сломаются символы /, ? и &.