Вызов внешнего API из кода 1С: HTTP-запросы, JSON, WSПрокси и HTTPS
Содержание
Чтобы обратиться к веб-сервису
из 1С 8.3, в коде создают объект HTTPСоединение (адрес сервера, порт, таймаут, защищённое соединение), к нему — HTTPЗапрос с адресом ресурса и заголовками, и вызывают метод Получить() для GET или ОтправитьДляОбработки() для POST. Ответ приходит объектом HTTPОтвет: код состояния и тело, которое разбирают через ЧтениеJSON или ЧтениеXML. Для SOAP-сервисов вместо этого используют WSОпределения и WSПрокси.
Типичная ситуация: бухгалтер просит подтягивать курсы из банка, статусы доставки или остатки с маркетплейса прямо в базу. Программисту нужно настроить интеграцию 1С с внешним API так, чтобы она не зависала, не теряла кириллицу и честно сообщала об ошибках. Всё ниже относится к платформе 8.3 и не зависит от конфигурации: БП, ЗУП, УТ или самописная база работают с веб-сервисами одинаково.
Подготовка: где выполнять код и что проверить до первой строки
Запросы к внешним сервисам выполняют на сервере — в процедурах с директивой &НаСервере или в общих модулях с флагом «Сервер». Тогда доступ в интернет нужен одной машине, а не каждому пользователю.
Что проверить заранее:
- 🌐 Сеть сервера 1С. В клиент-серверном варианте запрос уходит с компьютера, где работает рабочий процесс
rphost. В файловом — с компьютера пользователя. Брандмауэр и прокси настраивают именно там. - 🔑 Документация API. Нужны базовый адрес, способ авторизации (логин и пароль, токен, ключ в заголовке), формат тела и список кодов ответа.
- 🧪 Проверка вне 1С. Отправьте тот же запрос из Postman или
curlс сервера 1С. Если он не проходит там, искать ошибку в коде бессмысленно. - 🛡️ Профили безопасности. Если в кластере включены профили безопасности, профилю базы нужно разрешить доступ к интернет-ресурсам, иначе платформа заблокирует соединение.
Команда curl -v https://api.example.ru/v1/ping, запущенная на сервере 1С, сразу покажет, резолвится ли имя, проходит ли TLS-рукопожатие и что отвечает сервис. Это пять секунд вместо часа отладки.
Параметры HTTPСоединения
Конструктор принимает параметры по порядку:
| Параметр | Что передавать | Пример |
|---|---|---|
| Сервер | Только имя хоста, без https:// и пути | "api.example.ru" |
| Порт | Обычно не указывают: 80 для HTTP, 443 для HTTPS | 443 |
| Пользователь, Пароль | Для Basic-авторизации | "login", "secret" |
| Прокси | Объект ИнтернетПрокси или Неопределено | Новый ИнтернетПрокси(Истина) |
| Таймаут | Секунды ожидания; 0 — ждать бесконечно | 30 |
| ЗащищенноеСоединение | Объект ЗащищенноеСоединениеOpenSSL для HTTPS | Новый ЗащищенноеСоединениеOpenSSL() |
Никогда не оставляйте таймаут равным нулю. Если сервис зависнет, вместе с ним зависнет сеанс пользователя или регламентное задание.
Новый ИнтернетПрокси(Истина) берёт системные настройки прокси сервера. Если прокси в организации требует отдельного логина, создайте объект с параметром Ложь и задайте адрес методом Установить().
Формирование и отправка запроса к веб-сервису
Адрес ресурса в HTTPЗапрос — это всё, что идёт после имени сервера: путь и параметры. Заголовки передают соответствием.
GET: получить данные
&НаСервере
Функция ПолучитьЗаказ(НомерЗаказа)
Защищенное = Новый ЗащищенноеСоединениеOpenSSL();
Соединение = Новый HTTPСоединение("api.example.ru", , , , , 30, Защищенное);
Заголовки = Новый Соответствие;
Заголовки.Вставить("Accept", "application/json");
Заголовки.Вставить("Authorization", "Bearer " + ТокенДоступа());
Адрес = "/v1/orders/" + КодироватьСтроку(НомерЗаказа, СпособКодированияСтроки.КодировкаURL);
Запрос = Новый HTTPЗапрос(Адрес, Заголовки);
Ответ = Соединение.Получить(Запрос);
Возврат Ответ;
КонецФункции
Значения, которые подставляются в адрес, пропускайте через КодироватьСтроку(). Кириллица, пробелы и знак & в параметрах иначе ломают запрос.
POST: отправить JSON
&НаСервере
Функция СоздатьЗаказ(ДанныеЗаказа)
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, ДанныеЗаказа); // Структура или Соответствие
ТелоЗапроса = Запись.Закрыть();
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Заголовки.Вставить("Authorization", "Bearer " + ТокенДоступа());
Запрос = Новый HTTPЗапрос("/v1/orders", Заголовки);
Запрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8,
ИспользованиеByteOrderMark.НеИспользовать);
Соединение = Новый HTTPСоединение("api.example.ru", , , , , 30,
Новый ЗащищенноеСоединениеOpenSSL());
Возврат Соединение.ОтправитьДляОбработки(Запрос);
КонецФункции
Две детали, на которых спотыкаются чаще всего:
- BOM. Без параметра
ИспользованиеByteOrderMark.НеИспользоватьв начало тела может попасть служебная метка UTF-8. Многие сервисы отвечают на неё ошибкой разбора JSON. - Content-Type. Без него часть API возвращает
415 Unsupported Media Typeили принимает тело как пустое.
Какой метод соединения выбрать
| HTTP-метод | Метод HTTPСоединения | Когда нужен |
|---|---|---|
| GET | Получить() | Прочитать данные |
| POST | ОтправитьДляОбработки() | Создать объект, отправить команду |
| PUT | Записать() | Заменить объект целиком |
| DELETE | Удалить() | Удалить объект |
| PATCH и другие | ВызватьHTTPМетод("PATCH", Запрос) | Частичное изменение |
Авторизация
- 👤 Basic. Передайте логин и пароль третьим и четвёртым параметрами
HTTPСоединение— платформа сама сформирует заголовок. - 🎫 Токен. Заголовок
Authorization: Bearer <токен>. Если токен живёт ограниченное время, получайте его отдельным запросом и храните до истечения срока. - 🗝️ API-ключ. Чаще всего — собственный заголовок вроде
X-API-Key. Название берите из документации сервиса.
Токены и пароли не пишите в код модуля. Храните их в константе с ограниченными правами или в безопасном хранилище, если в конфигурации есть БСП: там для этого предусмотрены функции общего модуля ОбщегоНазначения.
Разбор ответа сервера: JSON и XML
Сначала проверьте код состояния, потом читайте тело. Успешные коды лежат в диапазоне 200–299: сервис может вернуть 200, 201 или 204 в зависимости от операции.
Ответ = ПолучитьЗаказ("A-1024");
Если Ответ.КодСостояния < 200 Или Ответ.КодСостояния > 299 Тогда
ВызватьИсключение СтрШаблон("Сервис вернул код %1: %2",
Формат(Ответ.КодСостояния, "ЧГ=0"),
Лев(Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8), 500));
КонецЕсли;
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
Данные = ПрочитатьJSON(Чтение, Истина); // Истина — читать в Соответствие
Чтение.Закрыть();
Статус = Данные.Получить("status");
Сумма = Данные.Получить("total");
Почему читать в Соответствие, а не в Структуру: ключи JSON бывают с дефисами, цифрами в начале или латиницей в разном регистре. Структура такие ключи не примет, и чтение упадёт.
Кодировку в ПолучитьТелоКакСтроку() указывайте явно. Если сервис не прислал её в заголовке Content-Type, платформа может прочитать UTF-8 как другую кодировку — и в документах появятся «кракозябры».
Даты, числа и пустые значения
- 📅 Даты в JSON — это строки. Для формата ISO 8601 используйте функцию
ПрочитатьДатуJSON(Строка, ФорматДатыJSON.ISO). - 🔢 Числа приходят числами, но идентификаторы иногда бывают строками. Не сравнивайте
"1024"с1024. - ∅
nullпревращается вНеопределено. Проверяйте значение перед записью в реквизит.
XML-ответ
Для XML есть два пути. Простой — ЧтениеXML и обход узлов в цикле. Удобный — ФабрикаXDTO.ПрочитатьXML(Чтение): получится объект XDTO, к свойствам которого обращаются через точку. Второй путь хорош, если у сервиса есть XSD-схема и её загрузили в конфигурацию как пакет XDTO.
Сопоставление полей стоит зафиксировать ещё до кода: какое поле API куда ложится в 1С и как искать ссылку. Это снимает половину вопросов при тестировании.
Работа с SOAP-веб-сервисом из 1С
SOAP-сервисы описаны WSDL-файлом. 1С умеет прочитать его и построить прокси-объект, у которого операции сервиса становятся методами.
Динамическое подключение
&НаСервере
Функция КурсВалюты(КодВалюты, ДатаКурса)
Определения = Новый WSОпределения("https://service.example.ru/rates?wsdl",
"login", "secret", , 30, Новый ЗащищенноеСоединениеOpenSSL());
Прокси = Новый WSПрокси(Определения,
"http://example.ru/rates", // URI пространства имён из WSDL
"RatesService", // имя сервиса
"RatesServiceSoap", // имя точки подключения
, 30, Новый ЗащищенноеСоединениеOpenSSL());
Прокси.Пользователь = "login";
Прокси.Пароль = "secret";
Возврат Прокси.GetRate(КодВалюты, ДатаКурса);
КонецФункции
Пространство имён, имя сервиса и точку подключения берите из WSDL: атрибут targetNamespace, элемент service и его port. Ошибка в любом из трёх значений даёт исключение уже на создании прокси.
Статическая WS-ссылка
Второй вариант — добавить WSDL в конфигурацию: в Конфигураторе ветка Общие → WS-ссылки, команда добавления с указанием адреса WSDL. Тогда описание хранится в конфигурации и не скачивается при каждом вызове.
| Способ | Плюсы | Минусы |
|---|---|---|
WSОпределения в коде | Не меняет конфигурацию, адрес можно хранить в настройках | WSDL скачивается при каждом создании, лишняя задержка |
| WS-ссылка в конфигурации | Быстрее, видна структура типов | Нужно менять конфигурацию; для типовой — через расширение |
Для типовой конфигурации WS-ссылку добавляют в расширение, чтобы не снимать основную конфигурацию с поддержки.
Если создание WSОпределения долгое, кэшируйте прокси в пределах одного вызова: создайте его один раз и вызывайте операции в цикле, а не пересоздавайте на каждой строке.
Обработка ошибок при обращении к веб-сервису
Ошибки бывают двух видов. Сетевые — соединение не установлено вовсе, платформа выбрасывает исключение. Прикладные — сервис ответил, но кодом 4xx или 5xx.
Попытка
Ответ = Соединение.Получить(Запрос);
Исключение
ЗаписьЖурналаРегистрации("Интеграция.API заказов",
УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Сервис заказов недоступен. Подробности — в журнале регистрации.";
КонецПопытки;
Журнал регистрации нужен, чтобы через месяц понять, что случилось. Пользователь видит короткое сообщение, администратор — полный текст в Администрирование → Обслуживание → Журнал регистрации с отбором по событию.
Что означают коды ответа
| Код | Смысл | Что делать |
|---|---|---|
| 400 | Сервис не понял тело запроса | Сравнить JSON с примером из документации |
| 401 | Нет авторизации или токен истёк | Обновить токен, проверить заголовок |
| 403 | Доступ запрещён | Проверить права ключа, IP в белом списке |
| 404 | Ресурс не найден | Проверить путь и идентификатор |
| 429 | Слишком много запросов | Сделать паузу, уменьшить частоту |
| 500, 502, 503 | Сбой на стороне сервиса | Повторить позже |
Повторы при 429 и 5xx лучше делать не в цикле внутри одного вызова, а через регламентное задание: оно запустится по расписанию и подберёт неотправленное.
Тексты сетевых ошибок платформа берёт из сетевой библиотеки, поэтому они приходят на английском внутри русского сообщения об ошибке работы с интернетом.
HTTPS и безопасность данных при интеграции
Для HTTPS в соединение передают объект ЗащищенноеСоединениеOpenSSL. Без него запрос пойдёт по открытому HTTP или не пройдёт вовсе, если сервис принимает только защищённые соединения.
Проверка сертификата сервера
Новый ЗащищенноеСоединениеOpenSSL() без параметров шифрует трафик, но не проверяет, что сертификат сервера выдан доверенным центром. Для обмена с банком, ЭДО или платёжным сервисом проверку стоит включить:
Защищенное = Новый ЗащищенноеСоединениеOpenSSL( ,
Новый СертификатыУдостоверяющихЦентровWindows());
Тогда платформа сверит сертификат сервиса с хранилищем корневых сертификатов Windows. Если сервис использует сертификат российского удостоверяющего центра, его корневой сертификат должен быть установлен в хранилище на сервере 1С. Для Linux-сервера сертификаты центров передают файлом через СертификатыУдостоверяющихЦентровФайл.
Клиентский сертификат
Некоторые банковские API требуют двусторонний TLS. Тогда в первый параметр ЗащищенноеСоединениеOpenSSL передают клиентский сертификат: СертификатКлиентаФайл с путём к файлу и паролем или СертификатКлиентаWindows из хранилища.
Минимум правил безопасности
- 🔒 Только HTTPS для любых данных с персональными сведениями, суммами и реквизитами.
- 🗄️ Токены и пароли — в защищённом хранилище, не в коде и не в общедоступных константах.
- 📝 В журнал регистрации пишите текст ошибки, но не токены и не тела с персональными данными.
- 👥 Отдельная учётная запись API для 1С с минимально нужными правами.
Как не уронить базу: таймауты, фон и регламентные задания
Синхронный запрос из формы блокирует пользователя, пока сервис думает. Если обмен занимает больше пары секунд, вынесите его в фоновое задание или регламентное.
Для массовых операций уточните у сервиса лимиты: сколько запросов в секунду и сколько записей в одном пакете. Отправка 5000 позиций по одной займёт 5000 соединений; пакетами по 100 — 50.
Частые вопросы об интеграции 1С с веб-сервисами
Чем исходящий запрос отличается от HTTP-сервиса 1С?
С какой версии платформы есть ЧтениеJSON?
Можно ли вызвать веб-сервис с клиента?
Как посмотреть, что реально уходит в сервис?
Как отправить файл в API?
УстановитьТелоИзДвоичныхДанных() для сырого файла. Для multipart/form-data тело собирают вручную с разделителем boundary и указывают его в Content-Type.