Отправка GET-запроса к внешнему API из 1С 8.3
Содержание
GET-запрос из 1С отправляют тремя объектами: HTTPСоединение (куда подключаемся), HTTPЗапрос (что запрашиваем) и метод Получить(), который возвращает HTTPОтвет. Тело ответа чаще всего приходит в JSON — его читают через объект ЧтениеJSON и функцию ПрочитатьJSON.
Ниже — рабочий код на встроенном языке, который подключается к внешнему API по HTTPS, забирает данные, разбирает JSON в Соответствие и корректно реагирует на коды ответа и сбои сети. Весь код выполняется на стороне сервера или в фоновом задании: прямое обращение к внешним ресурсам с клиента в большинстве случаев недоступно.
Что понадобится и из каких объектов собирается запрос
Для обращения к HTTP-сервису достаточно штатной платформы 8.3 — никаких внешних компонент. Код размещают в серверной процедуре общего модуля (флаг Сервер) либо в модуле объекта.
Три кирпича, из которых строится любой запрос:
- 🔌
HTTPСоединение— адрес сервера, порт, таймаут и признак защищённого соединения. - 📨
HTTPЗапрос— путь к ресурсу (без домена) и заголовки. - 📥
HTTPОтвет— то, что вернул методПолучить(): код состояния, заголовки и тело.
Важно сразу разделить адрес на части. В конструктор HTTPСоединение идёт только домен — без https:// и без пути. А путь с параметрами (всё, что после домена) передаётся в HTTPЗапрос.
Для HTTPS в последний значимый параметр конструктора передавайте Новый ЗащищенноеСоединениеOpenSSL. Без него подключение к адресу на 443-м порту завершится ошибкой проверки сертификата.
Порт зависит от протокола: 443 для HTTPS, 80 для обычного HTTP. Если порт не указать явно, платформа подставит значение по умолчанию, но лучше задавать его осознанно.
Собираем и отправляем GET-запрос
Минимальный рабочий пример — подключение к API и получение тела ответа строкой:
Функция ПолучитьЗаказы()
Соединение = Новый HTTPСоединение(
"api.example.com", // только домен, без http:// и пути
443, // 443 — HTTPS, 80 — HTTP
, // пользователь
, // пароль
, // прокси
30, // таймаут, секунд
Новый ЗащищенноеСоединениеOpenSSL); // обязательно для HTTPS
Запрос = Новый HTTPЗапрос("/v1/orders?status=new");
Запрос.Заголовки.Вставить("Accept", "application/json");
Ответ = Соединение.Получить(Запрос);
Возврат Ответ;
КонецФункции
Разберём по шагам, что здесь происходит:
- Создаём соединение с доменом
api.example.com. Таймаут 30 секунд — разумная граница: если сервер молчит дольше, запрос прервётся с исключением, а не повиснет. - Создаём запрос и в адресе ресурса указываем путь
/v1/ordersвместе со строкой параметров?status=new. - Через коллекцию
ЗаголовкидобавляемAccept: application/json— сообщаем серверу, что ждём JSON. - Вызываем
Соединение.Получить(Запрос). Именно методПолучить()соответствует HTTP-методу GET.
Для других методов у объекта есть свои функции: ОтправитьДляОбработки() — это POST, Записать() — PUT, Удалить() — DELETE. Нас интересует GET, поэтому работаем с Получить().
Обращение к внешнему адресу из кода на клиенте платформа блокирует — выполняйте запрос на сервере. Если нужно показать результат пользователю, оберните серверный вызов в процедуру с директивой &НаСервере или запустите в фоновом задании для долгих выгрузок.
Читаем ответ сервера и разбираем JSON
У объекта HTTPОтвет три части, которые нужны почти всегда:
| Свойство / метод | Что возвращает |
|---|---|
КодСостояния | Число: 200 — успех, 404 — не найдено, 401 — нет авторизации |
ПолучитьТелоКакСтроку("UTF-8") | Тело ответа строкой в указанной кодировке |
ПолучитьТелоКакДвоичныеДанные() | Тело бинарно — для файлов, картинок, архивов |
Заголовки | Соответствие заголовков ответа |
Сначала всегда проверяют код состояния, и только при успехе разбирают тело. Чтение JSON идёт через отдельный объект:
Если Ответ.КодСостояния <> 200 Тогда
ВызватьИсключение "Сервер вернул код " + Ответ.КодСостояния;
КонецЕсли;
ТелоСтрокой = Ответ.ПолучитьТелоКакСтроку("UTF-8");
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ТелоСтрокой);
Данные = ПрочитатьJSON(Чтение); // по умолчанию вернёт Соответствие
Чтение.Закрыть();
Функция ПрочитатьJSON по умолчанию возвращает Соответствие — к значениям обращаются по ключу: Данные["id"], Данные["name"]. Если передать вторым параметром Ложь, платформа попытается собрать Структуру, но это сработает только когда все имена свойств — корректные идентификаторы (без пробелов, дефисов и цифры в начале). Надёжнее оставлять Соответствие.
Когда сервер возвращает массив объектов, обход выглядит так:
Для Каждого Строка Из Данные Цикл
Сообщить(Строка["number"] + " — " + Строка["sum"]);
КонецЦикла;
Всегда указывайте кодировку в ПолучитьТелоКакСтроку. Без параметра платформа берёт кодировку из заголовка Content-Type, а если сервер его не прислал — результат получится с «кракозябрами». Для большинства современных API это UTF-8.
Объект ЧтениеJSON после работы закрывают методом Закрыть() — он освобождает поток.
Параметры запроса и кодирование URL
Параметры GET-запроса передаются прямо в строке ресурса после знака ?, пары ключ=значение разделяются амперсандом &. Пока значения состоят из латинских букв и цифр, их можно писать как есть.
Проблемы начинаются, когда в параметр попадают пробелы, кириллица или спецсимволы (&, =, +, /). Такую строку нужно закодировать функцией КодироватьСтроку:
ИмяДляПоиска = КодироватьСтроку("Иванов Иван", СпособКодированияСтроки.КодировкаURL);
Запрос = Новый HTTPЗапрос("/search?name=" + ИмяДляПоиска + "&limit=50");
Кодируют значения параметров по отдельности, а не весь адрес целиком — иначе разделители ?, = и & тоже превратятся в коды и сервер не разберёт строку.
💡 Удобный приём для нескольких параметров — собирать их в цикле:
Параметры = Новый Структура;
Параметры.Вставить("name", "Иванов Иван");
Параметры.Вставить("city", "Москва");
ЧастиАдреса = Новый Массив;
Для Каждого КлючЗначение Из Параметры Цикл
Значение = КодироватьСтроку(КлючЗначение.Значение, СпособКодированияСтроки.КодировкаURL);
ЧастиАдреса.Добавить(КлючЗначение.Ключ + "=" + Значение);
КонецЦикла;
АдресРесурса = "/search?" + СтрСоединить(ЧастиАдреса, "&");
Запрос = Новый HTTPЗапрос(АдресРесурса);
Так адрес соберётся корректно при любом числе параметров, а каждое значение будет закодировано ровно один раз.
Авторизация: Basic, токен Bearer и заголовки
Закрытые API требуют авторизации. Способ зависит от сервиса, но большинство укладывается в два варианта, и оба передаются заголовком Authorization.
Токен Bearer — самый частый вариант у современных REST API. Токен выдаётся в личном кабинете сервиса и просто подставляется в заголовок:
Запрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);
Basic-авторизация — логин и пароль, склеенные через двоеточие и закодированные в Base64:
СтрокаДоступа = "user:password";
Двоичные = ПолучитьДвоичныеДанныеИзСтроки(СтрокаДоступа, "UTF-8");
Код64 = СтрЗаменить(Base64Строка(Двоичные), Символы.ПС, "");
Запрос.Заголовки.Вставить("Authorization", "Basic " + Код64);
Функция Base64Строка может вставлять переносы строк в длинный результат, поэтому их убирают СтрЗаменить(..., Символы.ПС, ""). Логин и пароль для Basic можно задать и прямо в конструкторе HTTPСоединение (3-й и 4-й параметры) — платформа сама сформирует заголовок.
Помимо авторизации серверу часто нужны дополнительные заголовки:
Accept— формат ответа, который мы ждём (application/json).User-Agent— некоторые серверы отклоняют запросы без него.X-Api-Keyили другой нестандартный заголовок — если так требует документация сервиса.
Токены и пароли не храните в тексте модуля в открытом виде. Выносите их в константу, защищённое хранилище или параметры сеанса. Код с логином попадает в выгрузку конфигурации и в историю хранилища — это утечка доступа.
Обрабатываем ошибки и отлаживаем соединение
Сетевой запрос падает по двум разным причинам, и реагировать на них нужно по-разному.
Первая — исключение. Сервер недоступен, истёк таймаут, не прошла проверка сертификата. Метод Получить() в этом случае вызывает исключение, поэтому вызов оборачивают в Попытка:
Попытка
Ответ = Соединение.Получить(Запрос);
Исключение
Текст = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("Обмен.API", УровеньЖурналаРегистрации.Ошибка,,, Текст);
ВызватьИсключение "Не удалось подключиться к сервису: " + Текст;
КонецПопытки;
Вторая — соединение прошло, но сервер ответил ошибкой. Здесь исключения не будет: запрос считается выполненным, а о проблеме говорит КодСостояния.
| Код | Что означает | Что проверить |
|---|---|---|
200 | Успех | Разбираем тело |
301 / 302 | Переадресация | Прочитать заголовок Location и повторить запрос по новому адресу |
400 | Неверный запрос | Параметры и формат адреса |
401 | Нет авторизации | Токен или логин в заголовке Authorization |
403 | Доступ запрещён | Прав токена не хватает для этого ресурса |
404 | Ресурс не найден | Путь после домена, опечатки в адресе |
500–503 | Сбой на стороне сервера | Повторить позже, проверить статус сервиса |
Платформа не переходит по редиректам 301/302 автоматически. Если сервис отвечает такими кодами, нужно вручную взять адрес из заголовка Location и отправить запрос заново.
Для отладки пригодятся простые приёмы:
- При любом коде читайте тело через
ПолучитьТелоКакСтроку("UTF-8")— сервер обычно присылает текст ошибки с пояснением (например,invalid tokenилиrate limit exceeded). - Пишите код ответа и тело в журнал регистрации — это быстрее, чем ловить сбой в бою.
- Проверьте тот же адрес в браузере или через
curl: если и там ошибка, проблема не в 1С, а в API или доступе. - Для сложных случаев поднимите локальный прокси (Fiddler, Charles) и укажите его в параметре «прокси» конструктора — увидите реальный трафик запроса и ответа.
Готовая диагностика по частым симптомам:
Новый ЗащищенноеСоединениеOpenSSL либо указан порт 80 вместо 443. Проверьте оба параметра конструктора.Authorization не добавлен. Проверьте формат: Bearer <токен> или Basic <base64>.HTTPЗапрос должен идти путь без домена — например /v1/orders, а не https://api.example.com/v1/orders.ПолучитьТелоКакСтроку не указана кодировка. Передайте "UTF-8" явным параметром.Постраничная выборка: когда данных много
API редко отдаёт всё одним ответом. Большие списки разбиваются на страницы, и за них отвечают параметры вроде page и limit (или offset и count — смотрите документацию конкретного сервиса). Признак того, что страницы кончились, сервис обычно возвращает в теле ответа: пустой массив, поле has_more: false или общее число записей.
Выборку собирают циклом, увеличивая номер страницы, пока сервер отдаёт данные:
Результат = Новый Массив;
Страница = 1;
Пока Истина Цикл
Адрес = "/v1/orders?limit=100&page=" + Страница;
Запрос = Новый HTTPЗапрос(Адрес);
Запрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния <> 200 Тогда
Прервать;
КонецЕсли;
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку("UTF-8"));
Порция = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
Если Порция.Количество() = 0 Тогда
Прервать; // страницы закончились
КонецЕсли;
Для Каждого Элемент Из Порция Цикл
Результат.Добавить(Элемент);
КонецЦикла;
Страница = Страница + 1;
КонецЦикла;
Добавляйте условие выхода из цикла и по номеру страницы (например, не больше 1000 итераций). Если сервер из-за сбоя всегда будет отдавать непустой ответ, бесконечный цикл повесит фоновое задание.
Для тяжёлых выгрузок такой перебор запускают в фоновом задании, а не в клиентском сеансе — пользователю не придётся ждать завершения у открытой формы.
Полный пример: запрос с токеном и разбором ошибок
Соберём всё вместе — функцию, которая подключается по HTTPS, авторизуется токеном, проверяет код ответа и возвращает разобранные данные. Такую заготовку удобно держать в общем модуле и переиспользовать:
Функция ЗапроситьДанные(ПутьРесурса, Токен) Экспорт
Соединение = Новый HTTPСоединение(
"api.example.com", 443, , , , 30,
Новый ЗащищенноеСоединениеOpenSSL);
Запрос = Новый HTTPЗапрос(ПутьРесурса);
Запрос.Заголовки.Вставить("Accept", "application/json");
Запрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);
Попытка
Ответ = Соединение.Получить(Запрос);
Исключение
ЗаписьЖурналаРегистрации("Обмен.API",
УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
ВызватьИсключение "Сервис недоступен: " + ОписаниеОшибки();
КонецПопытки;
ТелоСтрокой = Ответ.ПолучитьТелоКакСтроку("UTF-8");
Если Ответ.КодСостояния <> 200 Тогда
ВызватьИсключение "Код " + Ответ.КодСостояния + ": " + ТелоСтрокой;
КонецЕсли;
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ТелоСтрокой);
Данные = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
Возврат Данные;
КонецФункции
Обратите внимание на порядок: тело читают до проверки кода состояния, чтобы при ошибке подложить в исключение текст от сервера. Это экономит время на разборе: вместо сухого «код 401» в журнале окажется invalid or expired token.
Перед первым запуском к новому сервису пройдитесь по короткому списку — он снимает большинство причин, по которым запрос не доходит:
Частые вопросы
Можно ли отправить GET-запрос с клиента, а не с сервера?
Чем GET отличается от POST в коде 1С?
HTTPСоединение: GET — это Получить(), POST — ОтправитьДляОбработки(). У GET данные передаются в строке адреса, у POST — в теле запроса.Как передать несколько параметров в GET-запросе?
? и разделитель &: /search?name=...&city=...&limit=50. Каждое значение по отдельности кодируйте функцией КодироватьСтроку с видом КодировкаURL.Почему приходит пустой ответ, хотя код состояния 200?
КодСостояния уже произошло исключение. Прочитайте тело строкой с "UTF-8" и выведите его в сообщение или журнал.Нужны ли внешние компоненты для работы с HTTP?
HTTPСоединение, HTTPЗапрос, ЧтениеJSON входят в штатную платформу 8.3 — ничего доустанавливать не требуется.