Обращение к SOAP и HTTP-сервисам из встроенного языка 1С 8.3: код, заголовки, авторизация, ошибки

· 10 мин

Содержание

Вызвать Web-сервис из 1С можно двумя путями. Для SOAP-сервиса с описанием WSDL создают WSОпределения и WSПрокси, после чего операция сервиса вызывается как обычный метод: Прокси.ПолучитьКурс(Код). Для REST и HTTP-сервисов (в том числе HTTP-сервисов другой базы 1С) используют HTTPСоединение и HTTPЗапрос и сами разбирают ответ.

Выбор простой. Есть WSDL и сервис отвечает XML-конвертами SOAP — берите WSПрокси. Сервис принимает JSON по адресу вида /api/v1/orders — работайте через HTTPСоединение. Код ниже проверен на платформе 8.3 с интерфейсом «Такси» и общий для всех конфигураций: БП, ЗУП, УТ, ERP.

Подготовка: адрес сервиса, публикация и где выполнять код

Прежде чем писать код, соберите четыре вещи:

  • 🌐 адрес сервиса: для SOAP — ссылка на WSDL, для REST — сервер, порт и путь ресурса;
  • 🔑 способ входа: логин и пароль, токен или вход без авторизации;
  • 📄 описание операций: имена методов и параметров (из WSDL или документации API);
  • 🔒 протокол: http или https. От него зависит параметр защищенного соединения.

Если вызываемый сервис — тоже 1С

Web-сервис в другой базе 1С сначала публикуют на веб-сервере (Apache или IIS):

  1. Запустите Конфигуратор от имени администратора Windows — без этого публикация не запишет файлы.
  2. Откройте Администрирование → Публикация на веб-сервере.
  3. Задайте имя публикации, например trade, и каталог.
  4. Включите флажок «Публиковать Web-сервисы» и отметьте нужные сервисы в списке. Для HTTP-сервисов есть отдельный флажок на соседней вкладке.
  5. Нажмите «Опубликовать» и перезапустите веб-сервер, если программа предложит.

Проверьте публикацию браузером. WSDL открывается по адресу вида http://server/trade/ws/Exchange.1cws?wsdl, где Exchange.1cws — значение свойства «Имя файла публикации» у объекта Web-сервиса. HTTP-сервис отвечает по адресу http://server/trade/hs/<корневой URL>/<шаблон>.

Если браузер показывает XML с тегами definitions и portType — публикация работает. Ошибка 404 означает опечатку в адресе или неотмеченный сервис. Ошибка 401 — сервис жив, но ждёт логин и пароль пользователя базы.

Код — только на сервере

Объект WSПрокси недоступен в тонком и веб-клиенте. HTTPСоединение в тонком клиенте создать можно, но тогда логин и токен окажутся на компьютере пользователя. Поэтому вызов выносят в процедуру с директивой &НаСервере или в серверный общий модуль.

В клиент-серверном варианте запрос уходит с машины сервера 1С, а не с компьютера пользователя. Брандмауэр, прокси и корневые сертификаты нужно настраивать там. Это частая причина ситуации «в браузере открывается, из 1С нет».

Вызов SOAP-сервиса через WSОпределения и WSПрокси

Схема из трёх шагов: прочитать WSDL, создать прокси, вызвать операцию.

&НаСервере
Функция ПолучитьКурсВалюты(КодВалюты)

    АдресWSDL = "https://server.example.ru/trade/ws/Exchange.1cws?wsdl";
    ЗащСоединение = Новый ЗащищенноеСоединениеOpenSSL();

    Определения = Новый WSОпределения(АдресWSDL, "ws_user", "Пароль", , 30, ЗащСоединение);

    Прокси = Новый WSПрокси(Определения,
        "http://example.ru/exchange",  // URI пространства имен из WSDL
        "Exchange",                    // имя сервиса
        "ExchangeSoap",                // имя точки подключения
        , 30, ЗащСоединение);

    Прокси.Пользователь = "ws_user";
    Прокси.Пароль = "Пароль";

    Возврат Прокси.GetRate(КодВалюты);

КонецФункции

Где взять три строковых параметра WSПрокси:

ПараметрГде найти в WSDL
URI пространства именатрибут targetNamespace в корневом теге definitions
Имя сервисаатрибут name тега service
Имя точки подключенияатрибут name тега port внутри service

У сервисов, опубликованных из 1С, точек подключения обычно две: ИмяСервисаSoap и ИмяСервисаSoap12. Подойдёт любая.

Логин и пароль в WSОпределения нужны только для скачивания WSDL. Для вызова операций их задают отдельно — свойствами Прокси.Пользователь и Прокси.Пароль. Забыли — получите 401 уже на вызове метода.

Сложные параметры: объекты XDTO

Если операция ждёт не строку, а структуру (заказ с табличной частью), параметр создают через фабрику XDTO прокси:

Тип = Прокси.ФабрикаXDTO.Тип("http://example.ru/exchange", "Order");
Заказ = Прокси.ФабрикаXDTO.Создать(Тип);
Заказ.Number = "А-125";
Заказ.Sum = 15400;
Результат = Прокси.SendOrder(Заказ);

Имена типов и свойств берите из раздела types в WSDL, они чувствительны к регистру.

WS-ссылка вместо загрузки WSDL при каждом вызове

Новый WSОпределения каждый раз скачивает и разбирает WSDL. При сотнях вызовов в час это заметная задержка и лишняя точка отказа. Практики импортируют WSDL в конфигурацию один раз: в Конфигураторе ветка «Общие → WS-ссылки», команда добавления, указать адрес WSDL. Дальше прокси создают без сети:

Прокси = WSСсылки.Exchange.СоздатьWSПрокси("http://example.ru/exchange", "Exchange", "ExchangeSoap");
Прокси.ТочкаПодключения.Местоположение = "https://prod.example.ru/trade/ws/Exchange.1cws";

Вторая строка переключает адрес, например с тестового сервера на рабочий. Адрес держите в константе или справочнике настроек, а не в коде.

Как сформировать HTTP-запрос к Web-сервису: адрес и заголовки

Для REST-сервиса соединение и запрос — два разных объекта. HTTPСоединение описывает сервер, HTTPЗапрос — конкретный ресурс, заголовки и тело.

&НаСервере
Функция СоздатьСоединение()
    Возврат Новый HTTPСоединение(
        "api.example.ru",                     // только имя хоста, без https:// и пути
        443,
        , ,                                   // пользователь, пароль
        ,                                     // прокси
        30,                                   // таймаут, секунды
        Новый ЗащищенноеСоединениеOpenSSL()); // для https обязательно
КонецФункции

Три правила, на которых спотыкаются чаще всего:

  1. В первый параметр пишется только хост: api.example.ru. Схема https:// и путь /v1/orders туда не попадают.
  2. Для https нужен объект ЗащищенноеСоединениеOpenSSL. Если сервер подписан внутренним центром сертификации, передайте вторым параметром Новый СертификатыУдостоверяющихЦентровОС — платформа возьмёт корневые сертификаты из хранилища ОС.
  3. Таймаут 0 означает «ждать бесконечно». Зависший сервис подвесит сеанс или фоновое задание. Ставьте 30–60 секунд.

Заголовки передают соответствием:

Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Заголовки.Вставить("Accept", "application/json");

Запрос = Новый HTTPЗапрос("/v1/orders", Заголовки);

Параметры строки запроса дописывают к адресу ресурса. Значения с кириллицей и пробелами кодируйте:

Фильтр = КодироватьСтроку("ООО Ромашка", СпособКодированияСтроки.КодировкаURL);
Запрос = Новый HTTPЗапрос("/v1/clients?name=" + Фильтр + "&page=2", Заголовки);

Если сервис работает через корпоративный прокси, создайте Новый ИнтернетПрокси(Истина) — с флагом Истина он берёт системные настройки — и передайте пятым параметром соединения.

GET, POST, PUT и DELETE: методы вызова веб-сервиса

Каждому HTTP-методу соответствует свой метод HTTPСоединение:

HTTP-методМетод в 1СКогда используют
GETПолучить(Запрос)прочитать данные: список, карточку, статус
POSTОтправитьДляОбработки(Запрос)создать объект, отправить документ
PUTЗаписать(Запрос)заменить объект целиком
DELETEУдалить(Запрос)удалить объект
PATCH и любой другойВызватьHTTPМетод("PATCH", Запрос)частичное изменение

Тело запроса для POST собирают из структуры через ЗаписьJSON:

Данные = Новый Структура;
Данные.Вставить("number", "А-125");
Данные.Вставить("sum", 15400);

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

Запрос.УстановитьТелоИзСтроки(ТекстJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ = СоздатьСоединение().ОтправитьДляОбработки(Запрос);

Третий параметр ИспользованиеByteOrderMark.НеИспользовать убирает метку BOM в начале тела. Часть API на ней ломается и отвечает 400 «invalid JSON», хотя текст выглядит правильно.

Файлы передают иначе. Запрос.УстановитьИмяФайлаТела(ПутьКФайлу) отправит файл с диска без загрузки в память. Скачать большой ответ сразу в файл можно вторым параметром: Соединение.Получить(Запрос, ИмяВыходногоФайла).

Разбор ответа: коды состояния и тело

Метод соединения возвращает объект HTTPОтвет. Сначала смотрят код, потом тело:

Если Ответ.КодСостояния = 200 Или Ответ.КодСостояния = 201 Тогда
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
    Результат = ПрочитатьJSON(Чтение, Истина); // Истина — получить Соответствие
    Чтение.Закрыть();
Иначе
    ТекстОшибки = СтрШаблон("Сервис вернул %1: %2",
        Формат(Ответ.КодСостояния, "ЧГ=0"),
        Лев(Ответ.ПолучитьТелоКакСтроку(), 500));
    ВызватьИсключение ТекстОшибки;
КонецЕсли;

Второй параметр ПрочитатьJSON со значением Истина возвращает Соответствие вместо Структуры. Это спасает, когда ключи в JSON начинаются с цифры или содержат дефис: структура такие имена не примет, и чтение упадёт.

Что означает код ответа и что с ним делать:

КодСмыслДействие
200, 201успех, объект получен или созданразобрать тело
204успех без телатело не читать
400ошибка в запросепроверить JSON, обязательные поля, кодировку
401не авторизованпроверить логин, пароль, срок токена
403доступ запрещённе хватает прав у учётной записи
404ресурс не найденпроверить путь и имя публикации
429слишком много запросовподождать и повторить
500ошибка на стороне сервисасмотреть тело ответа и журнал сервиса
502, 503, 504шлюз или сервис недоступенповторить позже

Заголовки ответа лежат в соответствии Ответ.Заголовки. Например, Ответ.Заголовки.Получить("Retry-After") подскажет, сколько секунд ждать после 429. Регистр ключей у разных серверов разный, поэтому при отсутствии значения проверьте и вариант в нижнем регистре.

Код 500 и другие «плохие» коды не вызывают исключения. HTTPСоединение спокойно вернёт ответ, и код без проверки КодСостояния примет страницу ошибки за данные.

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

Способ входа определяет сервис, а не 1С. Встречаются четыре варианта.

Логин и пароль пользователя (Basic). Передайте их третьим и четвёртым параметрами HTTPСоединение или свойствами WSПрокси. Так вызывают сервисы другой базы 1С: подходит обычный пользователь информационной базы, под ним выполняется код операции. Заведите для интеграции отдельного пользователя с минимальными правами.

Заголовок Authorization вручную. Нужен, если сервис ждёт Basic-заголовок, а не запрос «логин-ответ»:

Строка64 = Base64Строка(ПолучитьДвоичныеДанныеИзСтроки("api_user:Пароль", КодировкаТекста.UTF8));
Строка64 = СтрЗаменить(СтрЗаменить(Строка64, Символы.ВК, ""), Символы.ПС, "");
Заголовки.Вставить("Authorization", "Basic " + Строка64);

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

Токен (Bearer). Большинство внешних API работает так:

  1. Отправьте POST на адрес выдачи токена с логином и секретом.
  2. Сохраните токен и время окончания его действия.
  3. В каждый запрос добавляйте Заголовки.Вставить("Authorization", "Bearer " + Токен).
  4. Получили 401 — запросите новый токен и повторите запрос один раз. Второй 401 подряд — уже ошибка настройки, а не протухший токен.

Вход по учётной записи Windows. Восьмой параметр HTTPСоединение — ИспользоватьАутентификациюОС. Работает внутри домена, запрос пойдёт от имени пользователя, под которым запущен сервер 1С.

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

Ошибки, таймауты и повторные попытки

Сбои делятся на два класса, и обрабатывают их по-разному:

  • 🔌 сетевые: сервер недоступен, не прошло рукопожатие TLS, истёк таймаут. Здесь платформа вызывает исключение;
  • 📨 прикладные: сервис ответил, но с кодом 4xx или 5xx. Исключения нет, решение принимает ваш код по КодСостояния.

Для SOAP есть третий случай: ответ SOAP Fault. WSПрокси превращает его в исключение, текст которого содержит описание ошибки от сервиса.

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

Пишите ошибки в журнал регистрации под своим событием. Потом их легко отобрать фильтром по имени события.

Что повторять, а что нет

СитуацияПовторять?
таймаут, 502, 503, 504да, с паузой
429да, после паузы из Retry-After
401 по токенуодин раз, после обновления токена
400, 403, 404нет: повтор вернёт то же самое
5001–2 раза, затем разбор вручную

POST при повторе может создать дубль. Если ответ не дошёл из-за таймаута, сервис мог уже записать заказ. Повторяйте POST, только если API поддерживает ключ идемпотентности (обычно заголовок с уникальным идентификатором операции) или есть способ проверить, создан ли объект.

Паузы между попытками

Штатной процедуры «подождать N секунд» во встроенном языке нет, а пустой цикл грузит процессор сервера. Надёжная схема — очередь:

  1. Неудачную отправку записать в регистр сведений : объект, число попыток, время следующей попытки.
  2. Регламентное задание раз в несколько минут выбирает записи, у которых время подошло.
  3. После каждой неудачи интервал растёт: 1, 5, 15, 60 минут.
  4. После 5–6 попыток запись помечается как требующая разбора и попадает в отчёт ответственному.

Такая очередь переживает перезапуск сервера и не держит пользователя перед зависшей формой.

Диагностика: выберите симптом

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

Можно ли вызвать Web-сервис из тонкого клиента?
WSПрокси — нет, он доступен только на сервере и в толстом клиенте. Делайте серверную процедуру и вызывайте её с клиента.
Как посмотреть, что на самом деле уходит в сервис?
Направьте запрос на отладочный HTTP-прокси, например Fiddler, через объект ИнтернетПрокси, или временно выведите текст тела и заголовки в журнал регистрации. Пароли и токены перед записью маскируйте.
Как вызвать Web-сервис 1С из Postman или SoapUI для проверки?
В SoapUI создайте проект по адресу WSDL с ?wsdl на конце — он сам соберёт шаблоны запросов. В Postman для HTTP-сервиса укажите адрес /hs/... и Basic-авторизацию пользователем базы.
Почему из Конфигуратора в режиме отладки работает, а в регламентном задании нет?
Регламентное задание выполняется на сервере 1С под учётной записью службы. У неё может не быть доступа в интернет, к прокси или к корневым сертификатам, которые есть у вашего пользователя Windows.
Работает ли вызов Web-сервиса в файловой базе?
Да, код тот же. Разница одна: в файловом варианте серверный код выполняется на компьютере пользователя, поэтому запрос уходит оттуда, и сеть с сертификатами настраивают на каждом рабочем месте.