HTTP-сервис 1С — это обработчик внутри конфигурации, который отвечает на обычные HTTP-запросы: сайт, мобильное приложение, Python-скрипт или другая база 1С шлют GET или POST, а 1С возвращает JSON. В отличие от web-сервиса здесь нет SOAP и WSDL — только URL, метод и тело запроса. Ниже — полный цикл на платформе 8.3: как создать HTTP-сервис в конфигураторе, как устроены шаблоны URL и параметры, как принять и отдать JSON, опубликовать сервис на веб-сервере (в том числе из расширения), вызвать его из другой базы и отладить. В конце — таблица ошибок 404, 500 и 401 с причинами.
HTTP-сервис или web-сервис 1С: в чём разница
Оба объекта публикуют конфигурацию наружу, но устроены по-разному. Web-сервис работает по SOAP: клиент получает WSDL-описание, а обмен идёт XML-конвертами. HTTP-сервис ближе к REST: адрес ресурса, метод запроса и тело в любом формате, на практике — JSON.
| Критерий | HTTP-сервис | Web-сервис |
|---|---|---|
| Протокол | Чистый HTTP: GET, POST, PUT, DELETE | SOAP поверх HTTP |
| Формат данных | Любой, обычно JSON | XML по схеме XDTO |
| Описание для клиента | Нет, договорённость о формате | WSDL генерируется платформой |
| Адрес | /hs/<корневой URL>/<шаблон> | /ws/<имя> |
| Кому удобен | Сайт, мобильное приложение, Python, JS | Корпоративные шины и старые интеграции на SOAP |
Если с той стороны не 1С и не SOAP-клиент, берите HTTP-сервис: его можно вызвать из браузера, curl или requests без генерации прокси-классов.
Создание HTTP-сервиса в конфигураторе
HTTP-сервисы лежат в ветке «Общие → HTTP-сервисы». У объекта три уровня:
- Корневой URL — первая часть адреса после
/hs/, напримерapi. Обычно один корень на интеграцию. - Шаблоны URL — ресурсы внутри корня:
/products,/products/{code}. Фигурные скобки задают параметр пути, звёздочка в/products/*ловит любой хвост адреса. - Методы — у каждого шаблона свои: GET для чтения, POST для создания, PUT и DELETE по необходимости. Каждому методу назначается функция-обработчик в модуле сервиса.
Корневой URL и шаблон вместе дают адрес ресурса. Для корня api и шаблона /products/{code} товар с кодом 000000125 будет доступен по адресу http://сервер/база/hs/api/products/000000125. Префикс версии удобно вынести в корень (api/v1): тогда вторую версию можно поднять рядом, не ломая старых клиентов.
Обработчик всегда принимает объект HTTPСервисЗапрос и возвращает HTTPСервисОтвет. Первым в сервис стоит добавить проверочный шаблон /echo: по нему сразу видно, опубликован ли сервис, ещё до того, как написана логика.
Функция EchoGET(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки("OK", КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Возврат Ответ;
КонецФункции
Когда у ресурса несколько методов, обработчики в модуле сервиса удобно оставить однострочными, а разбор по Запрос.HTTPМетод вынести в общий модуль. Так вся логика ресурса и перехват ошибок живут в одном месте:
// Модуль HTTP-сервиса
Функция ProductsGET(Запрос)
Возврат HTTPСервисы.ProductsОбработатьЗапрос(Запрос);
КонецФункции
Функция ProductsPOST(Запрос)
Возврат HTTPСервисы.ProductsОбработатьЗапрос(Запрос);
КонецФункции
// Общий модуль HTTPСервисы
Функция ProductsОбработатьЗапрос(Запрос) Экспорт
ДанныеОтвета = СформироватьДанныеОтвета();
Попытка
Если Запрос.HTTPМетод = "GET" Тогда
Возврат ProductsGET(Запрос, ДанныеОтвета);
ИначеЕсли Запрос.HTTPМетод = "POST" Тогда
Возврат ProductsPOST(Запрос, ДанныеОтвета);
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("HTTPСервисы", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
Возврат ВернутьОшибку(ДанныеОтвета, "Внутренняя ошибка сервиса", 500);
КонецПопытки;
Возврат ВернутьОшибку(ДанныеОтвета, "Метод не поддерживается", 405);
КонецФункции
Полный текст ошибки уходит в журнал регистрации, а клиенту — короткое сообщение: стек вызовов и имена объектов конфигурации наружу отдавать незачем.
Параметры: путь, строка запроса и заголовки
Данные в HTTP-сервис приходят тремя путями, и у каждого своё свойство объекта запроса:
Запрос.ПараметрыURL— параметры из шаблона. Для/products/{code}значение берётся какЗапрос.ПараметрыURL.Получить("code").Запрос.ПараметрыЗапроса— всё, что после знака вопроса:?limit=50&status=new. Значения всегда строки, числа приводите сами.Запрос.Заголовки— служебные поля:Authorization,Content-Type, собственные ключи вродеX-Request-Id.
Правило, которое экономит часы отладки: идентификатор ресурса — в пути, фильтры и постраничность — в строке запроса. Один обработчик закрывает оба адреса: без кода в пути отдаёт весь список, с кодом — один товар.
Функция ProductsGET(Запрос, ДанныеОтвета)
Код = Запрос.ПараметрыURL.Получить("code");
Товары = СформироватьСписокТоваров(Код);
Если Код <> Неопределено И Товары.Количество() = 0 Тогда
Возврат ВернутьОшибку(ДанныеОтвета, "Товар не найден", 404);
КонецЕсли;
Возврат ВернутьДанные(ДанныеОтвета, Товары, 200);
КонецФункции
Функция СформироватьСписокТоваров(Код = Неопределено)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Код КАК Код,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Код = &Код";
Если Код = Неопределено Тогда
Запрос.Текст = СтрЗаменить(Запрос.Текст, "Номенклатура.Код = &Код", "ИСТИНА");
Иначе
Запрос.УстановитьПараметр("Код", Код);
КонецЕсли;
Товары = Новый Массив;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Товар = Новый Структура;
Товар.Вставить("uuid", XMLСтрока(Выборка.Ссылка));
Товар.Вставить("code", Выборка.Код);
Товар.Вставить("name", Выборка.Наименование);
Товары.Добавить(Товар);
КонецЦикла;
Возврат Товары;
КонецФункции
Ссылку на элемент справочника в JSON напрямую не записать, поэтому она уходит строкой через XMLСтрока(Выборка.Ссылка) — получается UUID, по которому клиент потом найдёт тот же товар. Функции ВернутьДанные и ВернутьОшибку — общие помощники модуля, они в следующем разделе.
POST и JSON: принять тело и вернуть ответ
Тело запроса читается методом ПолучитьТелоКакСтроку(), а разбор JSON делает ПрочитатьJSON. Второй параметр Истина вернёт соответствие, Ложь — структуру. Соответствие надёжнее: структура падает на ключах, которые не подходят под имена переменных 1С, например updated-at или 1c_code.
Функция ProductsPOST(Запрос, ДанныеОтвета)
ДанныеТовара = ПрочитатьСтрокуJSON(Запрос.ПолучитьТелоКакСтроку());
Если ДанныеТовара = Неопределено Тогда
Возврат ВернутьОшибку(ДанныеОтвета, "Тело запроса — не JSON", 400);
КонецЕсли;
Наименование = ДанныеТовара.Получить("name");
Если Не ЗначениеЗаполнено(Наименование) Тогда
Возврат ВернутьОшибку(ДанныеОтвета, "Не передан name", 422);
КонецЕсли;
НовыйТовар = Справочники.Номенклатура.СоздатьЭлемент();
НовыйТовар.Наименование = Наименование;
НовыйТовар.Записать();
Возврат ВернутьДанные(ДанныеОтвета, Новый Структура("code", НовыйТовар.Код), 201);
КонецФункции
Все ответы сервиса удобно собирать в один конверт: {"response": …, "error": null} при успехе и {"response": null, "error": "…"} при ошибке. Клиент всегда знает, где искать данные, а где текст ошибки. Помощники для этого — пять коротких функций общего модуля:
Функция СформироватьДанныеОтвета()
ДанныеОтвета = Новый Соответствие;
ДанныеОтвета.Вставить("response", Неопределено);
ДанныеОтвета.Вставить("error", Неопределено);
Возврат ДанныеОтвета;
КонецФункции
Функция ВернутьДанные(ДанныеОтвета, Данные, Код)
ДанныеОтвета["response"] = Данные;
Возврат СформироватьОтвет(ДанныеОтвета, Код);
КонецФункции
Функция ВернутьОшибку(ДанныеОтвета, Ошибка, Код)
ДанныеОтвета["error"] = Ошибка;
Возврат СформироватьОтвет(ДанныеОтвета, Код);
КонецФункции
Функция СформироватьОтвет(Данные, Код)
Ответ = Новый HTTPСервисОтвет(Код);
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Ответ.УстановитьТелоИзСтроки(ЗаписатьСтрокуJSON(Данные), КодировкаТекста.UTF8,
ИспользованиеByteOrderMark.НеИспользовать);
Возврат Ответ;
КонецФункции
Функция ЗаписатьСтрокуJSON(Данные) Экспорт
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет));
НастройкиСериализации = Новый НастройкиСериализацииJSON;
НастройкиСериализации.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.ЛокальнаяДатаСоСмещением;
НастройкиСериализации.ФорматСериализацииДаты = ФорматДатыJSON.ISO;
ЗаписатьJSON(ЗаписьJSON, Данные, НастройкиСериализации);
Возврат ЗаписьJSON.Закрыть();
КонецФункции
Разбор входящего тела — шестая функция. Битый JSON не роняет обработчик: функция пишет ошибку в журнал и возвращает Неопределено, а вызывающий код отвечает клиенту 400.
Функция ПрочитатьСтрокуJSON(СтрокаJSON, ИменаСвойствСДатами = Неопределено) Экспорт
Если Не ЗначениеЗаполнено(СтрокаJSON) Тогда
Возврат Неопределено;
КонецЕсли;
Попытка
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
Возврат ПрочитатьJSON(ЧтениеJSON, Истина, ИменаСвойствСДатами);
Исключение
ЗаписьЖурналаРегистрации("HTTPСервисы", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Три детали, которые чаще всего ломают интеграцию:
- BOM в начале тела. Без параметра
ИспользованиеByteOrderMark.НеИспользоватьчасть клиентов на JavaScript и Python падает на первом символе ответа. - Даты. Без настроек
ЗаписатьJSONпишет дату без часового пояса, и клиент в другой зоне сдвинет её на несколько часов. ВариантЛокальнаяДатаСоСмещениемдаёт2026-10-13T10:00:00+03:00. В обратную сторону даты сами не распознаются: имена свойств с датами нужно передать третьим параметромПрочитатьJSON, напримерupdated_atиdate, — тогда они придут типом «Дата», а не строкой. - Ссылки и перечисления. Напрямую в JSON они не пишутся — переводите в строку через
XMLСтрока, как в примере с товарами. Как сериализовать объекты целиком через XDTO и чем это отличается от ручного JSON, разобрано в статье про XDTO, XML и JSON в 1С.
Коды ответа выбирайте по смыслу, а не «всегда 200 с полем error»: 201 — создано, 400 — тело не разобрали, 404 — ресурса нет, 422 — данные не прошли проверку. Клиенту на той стороне так проще обработать ошибку, а в логах веб-сервера сразу видно, что пошло не так.
Файлы и картинки через HTTP-сервис
JSON — не единственный формат. Архив обмена, PDF или картинку сервис принимает методом ПолучитьТелоКакДвоичныеДанные(), а отдаёт через УстановитьТелоИзДвоичныхДанных():
Функция ОбменPOST(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Попытка
ДвоичныеДанные = Запрос.ПолучитьТелоКакДвоичныеДанные();
ДвоичныеДанные.Записать(КаталогВременныхФайлов() + "exchange.zip");
Ответ.УстановитьТелоИзСтроки("OK");
Исключение
ЗаписьЖурналаРегистрации("HTTPСервисы", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
Ответ.КодСостояния = 500;
Ответ.УстановитьТелоИзСтроки("Не удалось сохранить файл");
КонецПопытки;
Возврат Ответ;
КонецФункции
Функция КартинкаGET(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "image/png");
Ответ.УстановитьТелоИзДвоичныхДанных(БиблиотекаКартинок.Логотип.ПолучитьДвоичныеДанные());
Возврат Ответ;
КонецФункции
Заголовок Content-Type для двоичного ответа обязателен: без image/png браузер не покажет картинку, а скачает её как файл без расширения.
Со стороны клиента файл отправляется тем же HTTPЗапрос, только тело — двоичные данные, а в заголовке — их тип:
HTTPЗапрос = Новый HTTPЗапрос("/clientbase/hs/ex");
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/zip");
HTTPЗапрос.УстановитьТелоИзДвоичныхДанных(ПолучитьОбщийМакет("ФайлОбмена"));
Результат = Соединение.ВызватьHTTPМетод("POST", HTTPЗапрос);
Если файл большой, не держите его в памяти целиком: у HTTPЗапрос есть УстановитьИмяФайлаТела(), и платформа читает тело прямо с диска.
Публикация HTTP-сервиса на веб-сервере
Пока база не опубликована, сервис недоступен снаружи. Публикация делается из конфигуратора («Администрирование → Публикация на веб-сервере», флажок «Публиковать HTTP-сервисы») или утилитой webinst. Результат — файл default.vrd в каталоге публикации. Фрагмент, который отвечает за HTTP-сервисы:
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
base="/trade"
ib="Srvr="srv1c";Ref="trade";">
<httpServices publishByDefault="true" publishExtensionsByDefault="true">
<service name="API" rootUrl="api" enable="true"
reuseSessions="autouse" sessionMaxAge="20"
poolSize="10" poolTimeout="5"/>
</httpServices>
</point>
publishByDefaultпубликует все HTTP-сервисы конфигурации, даже не перечисленные явно.publishExtensionsByDefaultнужен, если сервис добавлен расширением. Без него сервис из расширения отдаёт 404, хотя в конфигураторе всё на месте.reuseSessionsуправляет переиспользованием сеансов: при частых коротких запросахautouseилиuseзаметно снижает задержку, потому что сеанс 1С не создаётся заново на каждый вызов.
Итоговый адрес: http://сервер/trade/hs/api/products/000000125. Установка Apache и IIS, модуль wsap24, SSL и CORS для вызова сервиса из браузера разобраны в отдельном руководстве по публикации 1С на веб-сервере.
Вызов HTTP-сервиса из другой базы 1С
Обмен между базами через HTTP-сервис — частый сценарий: розница спрашивает остатки у центральной базы, мобильная база шлёт заказы в учётную. На стороне клиента работают HTTPСоединение и HTTPЗапрос. Удобно держать одну функцию на все методы и ресурсы:
Функция ОтправитьHTTPЗапрос(Метод, АдресРесурса, Данные = Неопределено) Экспорт
Соединение = Новый HTTPСоединение("srv1c.local", 443, "exchange", ПарольОбмена(),
, 30, Новый ЗащищенноеСоединениеOpenSSL);
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса);
Если Данные <> Неопределено Тогда
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
HTTPЗапрос.УстановитьТелоИзСтроки(ЗаписатьСтрокуJSON(Данные), КодировкаТекста.UTF8,
ИспользованиеByteOrderMark.НеИспользовать);
КонецЕсли;
Результат = Соединение.ВызватьHTTPМетод(Метод, HTTPЗапрос);
Возврат Новый Структура("Код, Тело", Результат.КодСостояния, Результат.ПолучитьТелоКакСтроку());
КонецФункции
Чтение и создание товара:
Ответ = ОтправитьHTTPЗапрос("GET", "/trade/hs/api/products/000000125");
Ответ = ОтправитьHTTPЗапрос("POST", "/trade/hs/api/products",
Новый Структура("name", "Стол дубовый"));
Если Ответ.Код <> 201 Тогда
ВызватьИсключение СтрШаблон("Сервис вернул %1: %2", Ответ.Код, Ответ.Тело);
КонецЕсли;
КодТовара = ПрочитатьСтрокуJSON(Ответ.Тело)["response"]["code"];
ВызватьHTTPМетод принимает имя метода строкой, поэтому одна функция покрывает GET, POST, PUT, DELETE и PATCH. У старых методов соединения названия свои: Получить — это GET, ОтправитьДляОбработки — POST, Записать — PUT, Удалить — DELETE. ЗаписатьСтрокуJSON и ПрочитатьСтрокуJSON — те же помощники, что и на стороне сервиса: их удобно держать в общем модуле, который есть в обеих базах. Таймаут в 30 секунд задан явно: без него зависший сервис держит клиентский сеанс до разрыва соединения.
Когда систем больше двух и нужны гарантии доставки и повтор сообщений, прямых HTTP-вызовов «точка-точка» уже мало. Когда хватает HTTP-сервиса, а когда пора брать брокер сообщений, сравнивается в таблице статьи про Kafka REST Proxy и 1С. А если основную логику удобнее писать на Python, а 1С оставить источником данных, посмотрите схему микросервиса на FastAPI рядом с 1С.
Авторизация HTTP-сервиса
По умолчанию HTTP-сервис требует аутентификацию пользователем информационной базы: клиент передаёт логин и пароль в заголовке Authorization: Basic, а обработчик выполняется с правами этого пользователя. Для обмена между своими базами этого достаточно, если соединение идёт по HTTPS, а у пользователя обмена урезанная роль.
Для внешних клиентов Basic неудобен: пароль уходит в каждом запросе, отозвать доступ одному клиенту нельзя. Начиная с 8.3.21 платформа умеет выпускать и проверять JWT штатным объектом ТокенДоступа — пошаговый разбор с выдачей и проверкой токена есть в статье о JWT-авторизации в HTTP-сервисе 1С.
Отладка HTTP-сервисов
Точка останова в модуле HTTP-сервиса сама по себе не сработает: код выполняется в сеансе веб-сервера, а не в вашем клиенте. Порядок такой:
- Включите в конфигураторе отладку по протоколу HTTP («Сервис → Параметры → Отладка») и запустите сервер отладки.
- Добавьте в
default.vrdстроку<debug enable="true" protocol="http" url="http://localhost:1550"/>с адресом сервера отладки и перезапустите веб-сервер. - В конфигураторе откройте «Отладка → Подключение», в настройках автоматического подключения отметьте HTTP-сервисы.
- Поставьте точку останова и отправьте запрос из
curl, Postman или тестовой обработки.
На боевом сервере отладку держать включённой не стоит. Там первым делом смотрите журнал регистрации: необработанное исключение обработчика попадает туда с полным стеком.
Ошибки HTTP-сервиса: 404, 500, 401
| Ответ | Типичная причина | Что проверить |
|---|---|---|
| 404 | Сервис не опубликован или адрес собран неверно | Перепубликуйте базу после добавления сервиса; сверьте корневой URL и шаблон; для расширения — publishExtensionsByDefault |
| 404 от самой 1С | Адрес совпал с корнем, но ни один шаблон не подошёл | Слеш в начале шаблона, регистр, лишний сегмент пути |
| 500 | Исключение в обработчике или обработчик ничего не вернул | Журнал регистрации; каждая ветка функции должна возвращать HTTPСервисОтвет |
| 401 | Нет заголовка авторизации или неверная пара логин — пароль | Пользователь существует в базе, у него есть право входа, кодировка пароля в Basic |
| Клиент не разбирает ответ | BOM в начале тела или неверный Content-Type | ИспользованиеByteOrderMark.НеИспользовать и application/json; charset=utf-8 |
Где разобрать HTTP-сервисы на практике
Всё, что выше, — каркас: создание, параметры, JSON, публикация и вызов. В рабочей интеграции к нему добавляются версии API, журнал обмена, повторы при сбоях и защита от двойной отправки. Их удобнее один раз собрать руками на учебном проекте, чем чинить на живом обмене, — для этого есть курс по интеграции 1С через HTTP-сервисы.
HTTP-сервис — ещё и транспорт для ИИ-агентов: MCP-сервер внутри 1С публикуется именно так. Как это устроено, показано в разборе MCP-сервера для 1С.