Обращение к SOAP и HTTP-сервисам из встроенного языка 1С 8.3: код, заголовки, авторизация, ошибки
Содержание
Вызвать 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):
- Запустите Конфигуратор от имени администратора Windows — без этого публикация не запишет файлы.
- Откройте
Администрирование → Публикация на веб-сервере. - Задайте имя публикации, например
trade, и каталог. - Включите флажок «Публиковать Web-сервисы» и отметьте нужные сервисы в списке. Для HTTP-сервисов есть отдельный флажок на соседней вкладке.
- Нажмите «Опубликовать» и перезапустите веб-сервер, если программа предложит.
Проверьте публикацию браузером. 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 обязательно
КонецФункции
Три правила, на которых спотыкаются чаще всего:
- В первый параметр пишется только хост:
api.example.ru. Схемаhttps://и путь/v1/ordersтуда не попадают. - Для
httpsнужен объектЗащищенноеСоединениеOpenSSL. Если сервер подписан внутренним центром сертификации, передайте вторым параметромНовый СертификатыУдостоверяющихЦентровОС— платформа возьмёт корневые сертификаты из хранилища ОС. - Таймаут 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 работает так:
- Отправьте POST на адрес выдачи токена с логином и секретом.
- Сохраните токен и время окончания его действия.
- В каждый запрос добавляйте
Заголовки.Вставить("Authorization", "Bearer " + Токен). - Получили 401 — запросите новый токен и повторите запрос один раз. Второй 401 подряд — уже ошибка настройки, а не протухший токен.
Вход по учётной записи Windows. Восьмой параметр HTTPСоединение — ИспользоватьАутентификациюОС. Работает внутри домена, запрос пойдёт от имени пользователя, под которым запущен сервер 1С.
Секреты не хранят в тексте модуля и в обычных константах: их увидит любой, у кого есть доступ к Конфигуратору или права на чтение констант. В типовых конфигурациях на БСП для этого есть безопасное хранилище данных — запись и чтение только в привилегированном режиме.
Ошибки, таймауты и повторные попытки
Сбои делятся на два класса, и обрабатывают их по-разному:
- 🔌 сетевые: сервер недоступен, не прошло рукопожатие TLS, истёк таймаут. Здесь платформа вызывает исключение;
- 📨 прикладные: сервис ответил, но с кодом 4xx или 5xx. Исключения нет, решение принимает ваш код по
КодСостояния.
Для SOAP есть третий случай: ответ SOAP Fault. WSПрокси превращает его в исключение, текст которого содержит описание ошибки от сервиса.
Попытка
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Исключение
Описание = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("Интеграция.ОтправкаЗаказа",
УровеньЖурналаРегистрации.Ошибка, , , Описание);
Возврат Неопределено;
КонецПопытки;
Пишите ошибки в журнал регистрации под своим событием. Потом их легко отобрать фильтром по имени события.
Что повторять, а что нет
| Ситуация | Повторять? |
|---|---|
| таймаут, 502, 503, 504 | да, с паузой |
| 429 | да, после паузы из Retry-After |
| 401 по токену | один раз, после обновления токена |
| 400, 403, 404 | нет: повтор вернёт то же самое |
| 500 | 1–2 раза, затем разбор вручную |
POST при повторе может создать дубль. Если ответ не дошёл из-за таймаута, сервис мог уже записать заказ. Повторяйте POST, только если API поддерживает ключ идемпотентности (обычно заголовок с уникальным идентификатором операции) или есть способ проверить, создан ли объект.
Паузы между попытками
Штатной процедуры «подождать N секунд» во встроенном языке нет, а пустой цикл грузит процессор сервера. Надёжная схема — очередь:
- Неудачную отправку записать в регистр сведений : объект, число попыток, время следующей попытки.
- Регламентное задание раз в несколько минут выбирает записи, у которых время подошло.
- После каждой неудачи интервал растёт: 1, 5, 15, 60 минут.
- После 5–6 попыток запись помечается как требующая разбора и попадает в отчёт ответственному.
Такая очередь переживает перезапуск сервера и не держит пользователя перед зависшей формой.
Частые вопросы
Можно ли вызвать Web-сервис из тонкого клиента?
WSПрокси — нет, он доступен только на сервере и в толстом клиенте. Делайте серверную процедуру и вызывайте её с клиента.Как посмотреть, что на самом деле уходит в сервис?
ИнтернетПрокси, или временно выведите текст тела и заголовки в журнал регистрации. Пароли и токены перед записью маскируйте.Как вызвать Web-сервис 1С из Postman или SoapUI для проверки?
?wsdl на конце — он сам соберёт шаблоны запросов. В Postman для HTTP-сервиса укажите адрес /hs/... и Basic-авторизацию пользователем базы.