Напиши код на 1С который подключается к серверу iv...
बनाया गया: 11 सितंबर 2025
का उपयोग करके उत्तर दिया गया GPT-5 Thinking द्वारा Chat01
बनाया गया: 11 सितंबर 2025
का उपयोग करके उत्तर दिया गया GPT-5 Thinking द्वारा Chat01
Напиши код на 1С который подключается к серверу ivanti - ServiceDesk.WebAccess/wd с использованием api, запрос списка задач по техподдержке, создание новой задачи, изменение конкретной задачи
Ниже — «скелет» на 1С (8.3), который работает с REST-API Ivanti (Service Manager / Service Desk) через обычный HTTP-клиент: пример получения списка инцидентов (тикетов), создания нового и обновления конкретного. Код максимально универсален: вы задаёте базовый URL и нужные заголовки авторизации (Bearer-токен, Basic, X-API-Key — что настроено у вас).
Примечание по URL: в Ivanti Service Manager (HEAT) типовые OData-эндпоинты выглядят как
https://<host>/api/odata/businessobject/Incidents(плюс$top,$filterи т. п.). Структура URL и приёмы выборки описаны в документации Ivanti. В классическом Ivanti Service Desk (WebAccess/wd) REST доступ предоставляется фреймворком Service Desk и публикуется на том же хосте, но путь может отличаться от/wd— его уточняют администраторы при установке. (Ivanti Help)
1c// Универсальный вызов REST Функция ВызватьREST(БазовыйURL, Путь, Метод, ТелоJSONНеобязательный, ДопЗаголовкиНеобязательный) Экспорт Если Прав(БазовыйURL,1) = "/" Тогда БазовыйURL = Лев(БазовыйURL, СтрДлина(БазовыйURL)-1); КонецЕсли; Соединение = Новый HTTPСоединение(БазовыйURL); Запрос = Новый HTTPЗапрос(Путь); // Метод (GET/POST/PATCH/PUT/DELETE) Запрос.УстановитьМетод(Метод); // Базовые заголовки Запрос.Заголовки.Вставить("Accept", "application/json"); Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8"); // Позволяет работать даже если прокси/сервер не пропускает PATCH Если Метод = "PATCH" Тогда Запрос.Заголовки.Вставить("X-HTTP-Method-Override", "PATCH"); КонецЕсли; // Дополнительные заголовки (авторизация и т. п.) Если ТипЗнч(ДопЗаголовкиНеобязательный) = Тип("Соответствие") Тогда Для Каждого Пара Из ДопЗаголовкиНеобязательный Цикл Запрос.Заголовки.Вставить(Пара.Ключ, Пара.Значение); КонецЦикла; КонецЕсли; // Тело Если ЗначениеЗаполнено(ТелоJSONНеобязательный) Тогда Запрос.УстановитьТелоИзСтроки(ТелоJSONНеобязательный, "UTF-8"); КонецЕсли; Ответ = Соединение.Отправить(Запрос); Код = Ответ.КодСостояния(); Текст = Ответ.ПолучитьТелоКакСтроку(); // Попытка распарсить JSON Данные = Неопределено; Попытка Чт = Новый ЧтениеJSON; Чт.УстановитьСтроку(Текст); Данные = ПрочитатьJSON(Чт); Исключение // Вернём как есть КонецПопытки; Возврат Новый Структура("Код,Заголовки,Текст,Данные", Код, Ответ.Заголовки, Текст, Данные); КонецФункции; // Удобный конструктор заголовков авторизации Bearer Функция ЗаголовкиBearer(Токен) Экспорт Заг = Новый Соответствие; Заг.Вставить("Authorization", "Bearer " + Токен); Возврат Заг; КонецФункции;
Ivanti Service Manager (OData) пример:
1c// Возвращает первые N инцидентов со статусом Active Функция ПолучитьИнциденты_ISM(БазовыйURL, Токен, N) Экспорт Если N = Неопределено Тогда N = 50; Путь = "/api/odata/businessobject/Incidents?$top=" + Строка(N); Ответ = ВызватьREST(БазовыйURL, Путь, "GET", Неопределено, ЗаголовкиBearer(Токен)); Если Ответ.Код >= 200 И Ответ.Код < 300 Тогда Возврат Ответ.Данные; Иначе ВызватьИсключение "Ошибка получения инцидентов: " + Строка(Ответ.Код) + Символы.ПС + Ответ.Текст; КонецЕсли; КонецФункции;
(Структура URL’ов и выборки по бизнес-объектам Incidents через OData описана в справке Ivanti; там же есть варианты с $select, $filter, $orderby и т.п.) (Ivanti Help)
Примечание для классического Service Desk (WebAccess/wd): сам путь API отличается от /wd (путь /wd — это UI). REST-интерфейс публикуется сервисом «Service Desk Framework» как отдельное веб-приложение на том же IIS; конкретный базовый путь зависит от установки и открывается админами (часто доступ ограничён). В справке описано, что REST есть «из коробки» как часть Framework. (forums.ivanti.com)
1c// ПоляИнцидента — это Соответствие с парами "ИмяПоля" = Значение, // например: Subject, Description, Category, Priority и т.п. // Точные имена и обязательные поля зависят от вашей конфигурации Ivanti. Функция СоздатьИнцидент_ISM(БазовыйURL, Токен, ПоляИнцидента) Экспорт // Сериализация полей в JSON Зап = Новый ЗаписьJSON; Зап.УстановитьСтроку(); ЗаписатьJSON(ПоляИнцидента, Зап); Тело = Зап.ЗакрытьИПолучитьСтроку(); Путь = "/api/odata/businessobject/Incidents"; Ответ = ВызватьREST(БазовыйURL, Путь, "POST", Тело, ЗаголовкиBearer(Токен)); Если Ответ.Код = 201 Или Ответ.Код = 200 Тогда // Вернём ответ Ivanti (обычно содержит ключ/RecID созданного BO) Возврат Ответ.Данные; Иначе ВызватьИсключение "Ошибка создания инцидента: " + Строка(Ответ.Код) + Символы.ПС + Ответ.Текст; КонецЕсли; КонецФункции;
(В Ivanti SM через OData создают записи бизнес-объектов POST’ом в коллекцию объекта; см. разделы «Rest API» и примеры работы с бизнес-объектами.) (Ivanti Help)
1c// Обновляет поля инцидента по его уникальному ключу (RecID). // В OData коллекция называется "Incidents", а адрес записи — "/Incidents('<RecID>')". Процедура ОбновитьИнцидент_ISM(БазовыйURL, Токен, RecID, ПоляКОбновлению) Экспорт // Тело PATCH Зап = Новый ЗаписьJSON; Зап.УстановитьСтроку(); ЗаписатьJSON(ПоляКОбновлению, Зап); Тело = Зап.ЗакрытьИПолучитьСтроку(); Путь = "/api/odata/businessobject/Incidents('" + RecID + "')"; Заг = ЗаголовкиBearer(Токен); // Для некоторых конфигураций полезно If-Match:* (как в OData) Заг.Вставить("If-Match", "*"); Ответ = ВызватьREST(БазовыйURL, Путь, "PATCH", Тело, Заг); Если Ответ.Код >= 200 И Ответ.Код < 300 Тогда // Успех (часто тело пустое) Иначе ВызватьИсключение "Ошибка обновления инцидента: " + Строка(Ответ.Код) + Символы.ПС + Ответ.Текст; КонецЕсли; КонецПроцедуры;
(У Ivanti SM обновление записи бизнес-объекта выполняется через PATCH по адресу конкретной записи; на чтение/связи/фильтры — стандартные OData-паттерны. ) (Ivanti Help)
Вызовы выше ожидают заголовок Authorization: Bearer <token>. Как именно получить токен, зависит от вашей установки (он-прем или SaaS, локальная/внешняя публикация). Для SM есть официальные инструкции по работе с REST API и авторизацией (включая примеры с Postman). Если у вас Service Desk (WebAccess), то REST публикуется фреймворком SD — проверьте у админа точный базовый путь и схему аутентификации, т.к. внешнее открытие API может быть отключено. (Ivanti Help)
https://<ваш-хост> → далее /api/odata/businessobject/... (Incidents/Requests). (Ivanti Help)/wd; его публикует «Service Desk Framework» как отдельное приложение. Уточните реальный путь у администратора. (forums.ivanti.com)1cБазовыйURL = "https://sd.example.com"; Токен = "<ВАШ_BEARER_ТОКЕН>"; // 1) Список первых 20 инцидентов Список = ПолучитьИнциденты_ISM(БазовыйURL, Токен, 20); // 2) Создать инцидент (минимальный набор полей под вашу схему) Поля = Новый Соответствие; Поля.Вставить("Subject", "Печать не работает на 3 этаже"); Поля.Вставить("Description", "Принтер HP LJ 400 выдаёт ошибку 49.4C02"); Поля.Вставить("Category", "Hardware"); Новый = СоздатьИнцидент_ISM(БазовыйURL, Токен, Поля); // Предположим, что в ответе есть ключ RecID RecID = Новый["RecId"]; // или как поле называется в вашей схеме // 3) Обновить статус/приоритет КИзменению = Новый Соответствие; КИзменению.Вставить("Priority", "High"); КИзменению.Вставить("Status", "Assigned"); ОбновитьИнцидент_ISM(БазовыйURL, Токен, RecID, КИзменению);
/wd). (forums.ivanti.com)Если пришлёте ваш точный базовый URL API и схему авторизации (как вы логинитесь в API), подгоню примеры под вашу инсталляцию и добавлю фильтры/поля именно из вашей модели (например, поиск по группе поддержки, заявителю, по дате и т. п.).
проверь код на ошибки, добавь дополнительно аутентификацию по логину и паролю, которая соответствует ключам CURL -u и -d
Отлично, доработал пример: поправил потенциальные ошибки и добавил две опции аутентификации, как вы просили:
curl -u user:pass → Basic Auth (логин/пароль на каждый запрос)curl -u clientId:clientSecret -d ... → OAuth2 (получение Bearer-токена через form-POST)Ниже — цельный, аккуратно собранный модуль 1С (8.3) с комментариями.
1c//////////////////////////////////////////////////////////////////////////////// // Парсер базового URL (https/http, хост, порт, базовый путь) Функция РазобратьБазовыйURL(БазовыйURL) Экспорт // Нормализуем БазовыйURL = СокрЛП(БазовыйURL); ИспользоватьTLS = Ложь; Порт = 80; Хост = ""; БазовыйПуть = ""; // Определяем схему Если НСтр("ru='https://'", "en='https://'") = Лев(СтрЗаменить(СтрРег(БазовыйURL), "HTTPS://", "https://"), 8) Тогда ИспользоватьTLS = Истина; Порт = 443; Ост = Сред(БазовыйURL, 9); ИначеЕсли НСтр("ru='http://'", "en='http://'") = Лев(СтрЗаменить(СтрРег(БазовыйURL), "HTTP://", "http://"), 7) Тогда ИспользоватьTLS = Ложь; Порт = 80; Ост = Сред(БазовыйURL, 8); Иначе Ост = БазовыйURL; КонецЕсли; // Вырезаем хост[:порт] и начальный путь (если был) ПозСлэш = Найти(Ост, "/"); Если ПозСлэш = 0 Тогда ХостИПорт = Ост; Иначе ХостИПорт = Лев(Ост, ПозСлэш - 1); БазовыйПуть = Сред(Ост, ПозСлэш); КонецЕсли; ПозДвоеточие = Найти(ХостИПорт, ":"); Если ПозДвоеточие > 0 Тогда Хост = Лев(ХостИПорт, ПозДвоеточие - 1); Порт = Число(Сред(ХостИПорт, ПозДвоеточие + 1)); Иначе Хост = ХостИПорт; КонецЕсли; // Приводим путь к виду "/что-то/или пусто" Если Не ЗначениеЗаполнено(БазовыйПуть) Тогда БазовыйПуть = ""; Иначе Если Лев(БазовыйПуть, 1) <> "/" Тогда БазовыйПуть = "/" + БазовыйПуть; КонецЕсли; Если Прав(БазовыйПуть, 1) = "/" Тогда БазовыйПуть = Лев(БазовыйПуть, СтрДлина(БазовыйПуть) - 1); КонецЕсли; КонецЕсли; Возврат Новый Структура("Хост,Порт,ИспользоватьTLS,БазовыйПуть", Хост, Порт, ИспользоватьTLS, БазовыйПуть); КонецФункции; Функция СклеитьПуть(Левый, Правый) Если Не ЗначениеЗаполнено(Левый) Тогда Левый = ""; Если Не ЗначениеЗаполнено(Правый) Тогда Правый = ""; Если Левый = "" И Правый = "" Тогда Возврат "/"; КонецЕсли; Если Левый = "" Тогда Если Лев(Правый,1) = "/" Тогда Возврат Правый Иначе Возврат "/" + Правый; КонецЕсли; КонецЕсли; Если Прав(Левый,1) = "/" Тогда Левый = Лев(Левый, СтрДлина(Левый)-1); КонецЕсли; Если Лев(Правый,1) <> "/" Тогда Правый = "/" + Правый; КонецЕсли; Возврат Левый + Правый; КонецФункции; //////////////////////////////////////////////////////////////////////////////// // Кодирование (для -u и -d) Функция ToBase64(Стр) Экспорт // Эквивалент base64 из curl -u Возврат КодироватьСтроку(Стр, КодировкаСтроки.Base64); // 1С сама возьмёт UTF-8 КонецФункции; Функция UrlEncode(Стр) Экспорт Возврат КодироватьСтроку(Стр, КодировкаСтроки.URL); КонецФункции; //////////////////////////////////////////////////////////////////////////////// // Универсальный вызов REST (правильное создание HTTPСоединение) Функция ВызватьREST(БазовыйURL, Путь, Метод, ТелоСтрокаНеобязательный, ДопЗаголовкиНеобязательный, ЛогинBasicНеобязательный, ПарольBasicНеобязательный) Экспорт Парам = РазобратьБазовыйURL(БазовыйURL); Соединение = Новый HTTPСоединение(Парам.Хост, Парам.Порт, ?(ЗначениеЗаполнено(ЛогинBasicНеобязательный), ЛогинBasicНеобязательный, ""), ?(ЗначениеЗаполнено(ПарольBasicНеобязательный), ПарольBasicНеобязательный, ""), Парам.ИспользоватьTLS); ЛокПуть = СклеитьПуть(Парам.БазовыйПуть, Путь); Запрос = Новый HTTPЗапрос(ЛокПуть); // Метод Запрос.Метод = ?(ЗначениеЗаполнено(Метод), Метод, "GET"); // Заголовки по умолчанию Запрос.Заголовки.Вставить("Accept", "application/json"); // Тело / Content-Type Если ЗначениеЗаполнено(ТелоСтрокаНеобязательный) Тогда Если Не Запрос.Заголовки.Содержит("Content-Type") Тогда Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8"); КонецЕсли; Запрос.УстановитьТелоИзСтроки(ТелоСтрокаНеобязательный, "UTF-8"); КонецЕсли; // X-HTTP-Method-Override на случай блокировок PATCH/DELETE Если ВРег(Запрос.Метод) = "PATCH" Тогда Запрос.Заголовки.Вставить("X-HTTP-Method-Override", "PATCH"); КонецЕсли; // Доп. заголовки (в т.ч. Authorization) Если ТипЗнч(ДопЗаголовкиНеобязательный) = Тип("Соответствие") Тогда Для Каждого П Из ДопЗаголовкиНеобязательный Цикл Запрос.Заголовки.Вставить(П.Ключ, П.Значение); КонецЦикла; КонецЕсли; Ответ = Соединение.Отправить(Запрос); Код = Ответ.КодСостояния(); Текст = Ответ.ПолучитьТелоКакСтроку(); Данные = Неопределено; Попытка Чт = Новый ЧтениеJSON; Чт.УстановитьСтроку(Текст); Данные = ПрочитатьJSON(Чт); Исключение КонецПопытки; Возврат Новый Структура("Код,Заголовки,Текст,Данные", Код, Ответ.Заголовки, Текст, Данные); КонецФункции; //////////////////////////////////////////////////////////////////////////////// // Хелперы для авторизации Функция ЗаголовкиBearer(Токен) Экспорт Заг = Новый Соответствие; Заг.Вставить("Authorization", "Bearer " + Токен); Возврат Заг; КонецФункции; Функция ЗаголовкиBasic(Логин, Пароль) Экспорт Заг = Новый Соответствие; Заг.Вставить("Authorization", "Basic " + ToBase64(Логин + ":" + Пароль)); Возврат Заг; КонецФункции; //////////////////////////////////////////////////////////////////////////////// // OAuth2 (аналог curl -u clientId:clientSecret -d "grant_type=password&username=...&password=...") Функция ПолучитьOAuth2ТокенПароль(БазовыйURL, TokenPath, ClientID, ClientSecret, Username, Password, ScopeНеобязательный) Экспорт // Формируем form-urlencoded тело Поля = Новый Массив; Поля.Добавить("grant_type=" + UrlEncode("password")); Поля.Добавить("username=" + UrlEncode(Username)); Поля.Добавить("password=" + UrlEncode(Password)); Если ЗначениеЗаполнено(ScopeНеобязательный) Тогда Поля.Добавить("scope=" + UrlEncode(ScopeНеобязательный)); КонецЕсли; Тело = СтрСоединить(Поля, "&"); Заг = Новый Соответствие; Заг.Вставить("Authorization", "Basic " + ToBase64(ClientID + ":" + ClientSecret)); Заг.Вставить("Content-Type", "application/x-www-form-urlencoded"); Заг.Вставить("Accept", "application/json"); Ответ = ВызватьREST(БазовыйURL, TokenPath, "POST", Тело, Заг); Если Ответ.Код < 200 ИЛИ Ответ.Код >= 300 Тогда ВызватьИсключение "Не удалось получить токен OAuth2 (" + Строка(Ответ.Код) + "):" + Символы.ПС + Ответ.Текст; КонецЕсли; Если ТипЗнч(Ответ.Данные) = Тип("Соответствие") И Ответ.Данные.СодержитКлюч("access_token") Тогда Возврат Ответ.Данные["access_token"]; Иначе ВызватьИсключение "Ответ токен-эндпоинта не содержит access_token. Текст: " + Ответ.Текст; КонецЕсли; КонецФункции; //////////////////////////////////////////////////////////////////////////////// // Бизнес-операции (Ivanti Service Manager / OData) Функция ПолучитьИнциденты_ISM(БазовыйURL, ЗаголовкиAuth, N) Экспорт Если N = Неопределено Тогда N = 50; Путь = "/api/odata/businessobject/Incidents?$top=" + Строка(N); Ответ = ВызватьREST(БазовыйURL, Путь, "GET", Неопределено, ЗаголовкиAuth); Если Ответ.Код >= 200 И Ответ.Код < 300 Тогда Возврат Ответ.Данные; Иначе ВызватьИсключение "Ошибка получения инцидентов: " + Строка(Ответ.Код) + Символы.ПС + Ответ.Текст; КонецЕсли; КонецФункции; Функция СоздатьИнцидент_ISM(БазовыйURL, ЗаголовкиAuth, ПоляИнцидента) Экспорт Зап = Новый ЗаписьJSON; Зап.УстановитьСтроку(); ЗаписатьJSON(ПоляИнцидента, Зап); Тело = Зап.ЗакрытьИПолучитьСтроку(); Путь = "/api/odata/businessobject/Incidents"; // Content-Type уже выставится по умолчанию на application/json Ответ = ВызватьREST(БазовыйURL, Путь, "POST", Тело, ЗаголовкиAuth); Если (Ответ.Код = 201) ИЛИ (Ответ.Код = 200) Тогда Возврат Ответ.Данные; // обычно содержит RecID/URN и т.п. Иначе ВызватьИсключение "Ошибка создания инцидента: " + Строка(Ответ.Код) + Символы.ПС + Ответ.Текст; КонецЕсли; КонецФункции; Процедура ОбновитьИнцидент_ISM(БазовыйURL, ЗаголовкиAuth, RecID, ПоляКОбновлению) Экспорт Зап = Новый ЗаписьJSON; Зап.УстановитьСтроку(); ЗаписатьJSON(ПоляКОбновлению, Зап); Тело = Зап.ЗакрытьИПолучитьСтроку(); Путь = "/api/odata/businessobject/Incidents('" + RecID + "')"; Заг = Новый Соответствие; Для Каждого П Из ЗаголовкиAuth Цикл Заг.Вставить(П.Ключ, П.Значение); КонецЦикла; Заг.Вставить("If-Match", "*"); Ответ = ВызватьREST(БазовыйURL, Путь, "PATCH", Тело, Заг); Если Ответ.Код < 200 ИЛИ Ответ.Код >= 300 Тогда ВызватьИсключение "Ошибка обновления инцидента: " + Строка(Ответ.Код) + Символы.ПС + Ответ.Текст; КонецЕсли; КонецПроцедуры;
БазовыйURL: выделяются https/http, хост, порт и базовый путь. Раньше передавался полный URL в конструктор, что в ряде конфигураций приводит к ошибкам.Запрос.Метод, а не через неуниверсальный УстановитьМетод./api/... + ваш относительный Путь) сделана безопасно, без двойных/пропущенных слэшей.Новый (ключевое слово в 1С) — во всех примерах используются нейтральные имена.КодироватьСтроку(...).PATCH добавлен X-HTTP-Method-Override на случай ограничений прокси/IIS.curl -u user:passВариант А — через заголовок Authorization: Basic ...:
1cБазовыйURL = "https://sd.example.com"; Auth = ЗаголовкиBasic("api_user", "api_password"); // Пример чтения Список = ПолучитьИнциденты_ISM(БазовыйURL, Auth, 20);
Вариант Б — через параметры соединения (1С сама пришлёт Basic после 401):
1c// Можно прокинуть логин/пароль на уровень соединения, если нужен прямой вызов: Ответ = ВызватьREST(БазовыйURL, "/api/odata/businessobject/Incidents?$top=10", "GET", Неопределено, Неопределено, "api_user", "api_password");
curl -u clientId:clientSecret -d 'grant_type=password&username=...&password=...'1cБазовыйURL = "https://sd.example.com"; TokenPath = "/auth/connect/token"; // пример; укажите реальный путь токен-эндпоинта Токен = ПолучитьOAuth2ТокенПароль( БазовыйURL, TokenPath, "client_id", "client_secret", "api_user", "api_password", // это учётка Ivanti ""); // scope если требуется Auth = ЗаголовкиBearer(Токен); // Далее обычные вызовы с Bearer Набор = ПолучитьИнциденты_ISM(БазовыйURL, Auth, 20); Поля = Новый Соответствие; Поля.Вставить("Subject", "Тест из 1С"); Поля.Вставить("Description", "Создано REST API (1С)"); Созданный = СоздатьИнцидент_ISM(БазовыйURL, Auth, Поля); // Получаем RecID (название поля зависит от вашей конфигурации) Если ТипЗнч(Созданный) = Тип("Соответствие") И Созданный.СодержитКлюч("RecId") Тогда RecID = Созданный["RecId"]; Изм = Новый Соответствие; Изм.Вставить("Priority", "High"); Изм.Вставить("Status", "Assigned"); ОбновитьИнцидент_ISM(БазовыйURL, Auth, RecID, Изм); КонецЕсли;
Путь токен-эндпоинта (
TokenPath) и набор обязательных полей/ключей бизнес-объекта зависят от вашей инсталляции Ivanti (Service Manager vs Service Desk). Если у вас именно ServiceDesk.WebAccess/wd, помните:/wd— это UI, а REST публикуется фреймворком Service Desk как другое приложение на IIS (реальный API-путь уточните у администратора).
Если пришлёте ваш точный токен-эндпоинт и имена обязательных полей (Subject/Description/Category/... для Incidents), подгоню примеры фильтров ($filter, $select) и тела запросов точно под вашу схему.