Как получить адрес текущей публикации в HTTP-сервисе 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интеграционных решений на базе HTTP-сервисов в платформе 1С:Предприятие 8.3 часто возникает необходимость узнать точный адрес, по которому опубликован сервис. Это критически важно для формирования гиперссылок в ответах (например, ссылок на скачивание файлов или связанных ресурсов), для реализации редиректов или для корректной работы в распределенных системах. Рассмотрим подробно, как решить эту задачу, используя встроенные инструменты платформы и особенности протокола HTTP. Для ускорения реализации базовой логики обработчиков можно применить общий модуль для быстрой организации HTTP-сервисов.

Использование свойства БазовыйURL объекта HTTPСервисЗапрос

Самый простой и правильный способ получить адрес публикации внутри метода HTTP-сервиса — это обратиться к свойствам входящего запроса. Разберем по шагам, как это работает. Когда платформа принимает входящий вызов, она формирует объект типа HTTPСервисЗапрос. У этого объекта есть ключевое свойство БазовыйURL (на английском — BaseURL).

Проанализируем, что именно содержит БазовыйURL. Это строка, которая включает в себя:

  1. Протокол передачи данных (http или https).
  2. Имя хоста или IP-адрес сервера.
  3. Порт (если он отличается от стандартного 80 или 443).
  4. Имя публикации информационной базы на веб-сервере.
  5. Имя самого HTTP-сервиса (как оно задано в метаданных в конфигураторе).

Рассмотрим пример кода внутри метода обработки GET-запроса:


Функция ИмяМетодаGET(Запрос)
    // Получаем базовый адрес сервиса
    АдресПубликации = Запрос.БазовыйURL;
    
    // Результат будет выглядеть примерно так:
    // http://myserver.com/mybase/hs/MyServiceName
    
    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.УстановитьТелоИзСтроки("Адрес публикации: " + АдресПубликации);
    Возврат Ответ;
КонецФункции

Различия между БазовыйURL и ПолныйURL

Важно не путать свойство БазовыйURL со свойством ПолныйURL. Выясним причину этой путаницы. В то время как первый метод возвращает путь до корня сервиса, второй включает в себя абсолютно все данные запроса, включая относительный путь к конкретному ресурсу (шаблон URL) и параметры запроса (строка после знака вопроса).

Посмотрим на пример. Если клиент обращается по адресу: http://server/base/hs/service/v1/products?id=123, то:

Для формирования ссылок на другие методы этого же сервиса нам всегда следует использовать именно БазовыйURL.

Проблема обратных прокси (Reverse Proxy) и заголовков

Ситуация значительно усложняется, если ваша база 1С опубликована за промежуточным веб-сервером (например, Nginx, Apache или IIS), который выполняет роль прокси-сервера. Проанализируем проблему: в этом случае 1С работает "внутри" локальной сети, и свойство БазовыйURL может вернуть внутренний IP-адрес (например, http://10.0.0.5/...) вместо публичного доменного имени, которое видит клиент.

В таких случаях нам необходимо обратиться к коллекции Запрос.Заголовки. Разберем наиболее важные заголовки, которые помогут восстановить реальный адрес:

  1. Host — обязательный заголовок протокола HTTP/1.1. Он содержит доменное имя, которое указал клиент.
  2. X-Forwarded-Host — заголовок, который прокси-сервер добавляет для передачи оригинального хоста.
  3. X-Forwarded-Proto — указывает протокол (http или https), так как SSL-терминация часто происходит на прокси, и 1С может ошибочно считать, что запрос пришел по обычному HTTP.

Посмотрим на пример универсального получения адреса хоста:


Хост = Запрос.Заголовки.Получить("X-Forwarded-Host");
Если Хост = Неопределено Тогда
    Хост = Запрос.Заголовки.Получить("Host");
КонецЕсли;

Протокол = Запрос.Заголовки.Получить("X-Forwarded-Proto");
Если Протокол = Неопределено Тогда
    // Пытаемся определить по БазовыйURL
    Протокол = ?(Лев(Запрос.БазовыйURL, 5) = "https", "https", "http");
КонецЕсли;

Особенности работы в разделенном режиме (1С:Фреш)

Если вы разрабатываете решение для модели сервиса или используете области данных, платформа автоматически модифицирует URL. При обращении к конкретной области в адрес добавляется её идентификатор (например, /e1cib/data/123/).

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

Получение адреса публикации вне контекста запроса

Иногда возникает задача узнать адрес публикации в фоновом задании или при выполнении регламентных процедур, когда объекта Запрос просто не существует. Выясним, возможно ли это стандартными средствами.

К сожалению, в объектах метаданных 1С информация о том, где и как опубликована база, не хранится. Эта информация содержится в файле default.vrd на веб-сервере. Рассмотрим стратегии решения этой проблемы:

Итоговые рекомендации

Подводя итог, можно сказать, что для большинства задач внутри HTTP-сервиса достаточно использовать Запрос.БазовыйURL. Однако для высоконагруженных систем с балансировщиками и прокси-серверами всегда стоит предусмотреть логику анализа заголовка Host.

Важный момент: Если ваш сервис должен возвращать абсолютные ссылки на самого себя, всегда проверяйте соответствие протокола. Использование https в наше время является стандартом, и если ваша 1С "видит" только http из-за проксирования, не забудьте принудительно заменять протокол в возвращаемых строках, чтобы у клиента не возникало ошибок смешанного контента (Mixed Content).

Разберем финальный пример формирования ссылки на ресурс внутри сервиса:


// Предположим, нам нужно вернуть ссылку на файл с ID=456
ОтносительныйПутьКФайлу = "/files/get?id=456";

// Собираем полный путь
ПолныйПутьКРесурсу = Запрос.БазовыйURL + ОтносительныйПутьКФайлу;

// Если мы за прокси и нужен именно внешний адрес, используем Host
ВнешнийХост = Запрос.Заголовки.Получить("Host");
Если ВнешнийХост <> Неопределено Тогда
    // Находим начало пути после домена в БазовыйURL
    ПозицияСлэша = СтрНайти(Запрос.БазовыйURL, "/", , 3, 1); // Пропускаем http://
    ПутьПослеХоста = Сред(Запрос.БазовыйURL, ПозицияСлэша);
    ПолныйПутьКРесурсу = "https://" + ВнешнийХост + ПутьПослеХоста + ОтносительныйПутьКФайлу;
КонецЕсли;

Таким образом, комбинируя использование встроенного свойства БазовыйURL и анализ HTTP-заголовков, мы получаем гибкий и надежный инструмент для идентификации местоположения нашего сервиса в сети. Для проверки работы созданных методов и корректности передачи заголовков можно использовать обработку для тестирования HTTP-сервисов.

← На главную