HTTP-сервис: как настроить авторизацию (GET/POST) и почему возникает ошибка 500 при успешном выполнении?

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

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

Понимание механизма авторизации в HTTP-сервисах

Первая и самая распространенная ошибка при создании первого HTTP-сервиса — попытка прописать логин и пароль пользователя (например, "Администратор") непосредственно в коде обработки запроса (внутри функции сервиса). Давайте разберемся, почему это не работает.

Когда к опубликованному HTTP-сервису поступает запрос, процесс выглядит следующим образом:

  1. Веб-сервер (IIS или Apache) получает HTTP-запрос.
  2. Веб-сервер проверяет настройки публикации. Если включена аутентификация средствами ОС или 1С, он запрашивает учетные данные.
  3. Если учетные данные получены, веб-сервер передает управление платформе 1С:Предприятие.
  4. Платформа пытается запустить сеанс под указанным пользователем.
  5. Только если вход успешен, управление передается в ваш метод HTTP-сервиса (например, в функцию GetOrganizationList).

Следовательно, прописать авторизацию внутри функции GetOrganizationList невозможно, так как код этой функции начинает выполняться уже после того, как пользователь авторизован. Если авторизация не прошла на уровне веб-сервера/платформы, ваш код просто не будет вызван.

Варианты настройки авторизации

Рассмотрим два основных способа решения задачи доступа к сервису.

Вариант 1. Анонимный доступ (через публикацию)

Если нам нужно, чтобы сервис работал без запроса пароля у клиента (например, браузер сразу открывал JSON), необходимо указать пользователя в настройках публикации на веб-сервере. Это делается в файле default.vrd.

В строке подключения к информационной базе (атрибут ib) добавляются параметры usr и pwd:

ib="File="C:\Base1C";usr=ServiceUser;pwd=StrongPassword;"

В этом случае любой запрос к сервису будет автоматически выполняться под пользователем ServiceUser. Это удобно для отладки, но требует осторожности: пользователь должен иметь минимально необходимые права.

Вариант 2. Basic Authorization (передача логина и пароля клиентом)

Это стандартный и наиболее правильный способ для интеграции "1С — 1С". Клиент (в нашем случае "Комплексная автоматизация") должен передать заголовок Authorization. Для более продвинутых сценариев защиты также может применяться аутентификация стандартными средствами 1С с использованием Access и Refresh токенов.

При использовании объекта HTTPСоединение в 1С, это делается штатными средствами при создании соединения:


// Код на стороне клиента (кто вызывает сервис)
Сервер = "localhost";
Ресурс = "/DocMng/hs/Exchange/Organizations";
Пользователь = "Administrator"; // Пользователь базы, ГДЕ находится сервис
Пароль = "12345";

// Передаем логин и пароль в конструктор
Соединение = Новый HTTPСоединение(Сервер, , Пользователь, Пароль);

Запрос = Новый HTTPЗапрос(Ресурс);
Ответ = Соединение.Получить(Запрос);

При таком подходе 1С автоматически сформирует заголовок Authorization: Basic ..., закодировав логин и пароль в Base64.

Проблема с веб-сервером Apache: "вырезание" заголовков

В обсуждении была выявлена важная деталь: даже если вы правильно передаете логин и пароль, веб-сервер Apache может их игнорировать. Это происходит потому, что в некоторых конфигурациях (особенно при работе через FastCGI или CGI) Apache из соображений безопасности не передает заголовок Authorization скриптам. В сложных корпоративных средах также часто применяется публикация HTTP-сервиса с использованием клиентского SSL сертификата для обеспечения максимального уровня безопасности.

В результате платформа 1С не видит логина, считает запрос анонимным и (если анонимный доступ запрещен) возвращает ошибку 401, снова запрашивая пароль.

Решение:

Необходимо добавить специальную директиву в конфигурационный файл Apache (httpd.conf) или в файл .htaccess (если он обрабатывается):

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

Эта строка заставляет Apache принудительно копировать содержимое заголовка авторизации в переменную окружения, которую уже сможет прочитать платформа 1С.

Ошибка 500 при успешном выполнении действия

Рассмотрим ситуацию, описанную в финале обсуждения: документ в базе-приемнике успешно создается через POST-запрос, но клиент получает в ответ код 500 Internal Server Error. Подобный сценарий часто встречается, когда настраивается обмен с сайтом: POST запрос и создание счета с возвратом его номера в ответе. Ошибка 500 коварна тем, что бизнес-логика выполняется, но интеграция падает.

Давайте проанализируем возможные причины, особенно учитывая, что сервис написан в расширении конфигурации.

Причина 1: Безопасный режим расширения

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

Если ваш код (или код типовой конфигурации, который вызывается при записи документа) пытается выполнить операции, запрещенные в безопасном режиме (например, обращение к файловой системе, COM-объектам или привилегированному режиму особым образом), возникнет исключение.

Решение: Зайдите в свойства расширения в режиме "1С:Предприятие" (Администрирование -> Печатные формы, отчеты и обработки -> Расширения) и снимите галку "Безопасный режим".

Причина 2: Интерактивные вызовы в серверном коде

HTTP-сервис работает в фоновом режиме без участия пользователя. У него нет экрана.

При записи документа (метод ДокументОбъект.Записать()) часто срабатывают подписки на события или проверки в модуле объекта. Если в этом коде встречается:

...то сеанс аварийно завершается, так как "показать" сообщение некому. Платформа перехватывает это падение и возвращает клиенту HTTP-код 500.

Диагностика: Чтобы найти виновника, оберните код записи в Попытка ... Исключение и запишите ошибку в Журнал Регистрации:


Попытка
    НовыйДокумент.Записать();
Исключение
    ИнформацияОбОшибке = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
    ЗаписьЖурналаРегистрации("HTTPСервис.СозданиеДокумента", 
        УровеньЖурналаРегистрации.Ошибка, , , ИнформацияОбОшибке);
    
    // Возвращаем ошибку клиенту в JSON
    Ответ = Новый HTTPСервисОтвет(500);
    Ответ.УстановитьТелоИзСтроки(ИнформацияОбОшибке);
    Возврат Ответ;
КонецПопытки;

Причина 3: Ошибка сериализации ответа

Иногда документ записывается, но ошибка происходит в момент формирования ответа HTTPСервисОтвет. Например, если вы пытаетесь сериализовать в JSON объект, который не поддерживается (например, СправочникСсылка без преобразования или сложное перекрестное ссылочное дерево). Чтобы избежать таких проблем, рекомендуется использовать универсальные процедуры для быстрой организации API, которые берут на себя рутинные задачи по обработке данных.

Правильный пример формирования ответа в JSON

Рассмотрим корректный код метода GET, который возвращает список организаций, избегая лишних ошибок:


Функция GetOrganizationList(Запрос)
    
    // Устанавливаем заголовки ответа
    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.Заголовки.Вставить("Content-type", "application/json; charset=utf-8");
    
    // Получаем данные
    Запрос1С = Новый Запрос;
    Запрос1С.Текст = "ВЫБРАТЬ Код, Наименование, ИНН, КПП ИЗ Справочник.Организации";
    Выборка = Запрос1С.Выполнить().Выбрать();
    
    МассивОрганизаций = Новый Массив;
    
    Пока Выборка.Следующий() Цикл
        ДанныеОрганизации = Новый Структура;
        // Важно: приводим типы к простым (Строка, Число, Булево, Дата)
        ДанныеОрганизации.Вставить("Code",  XMLСтрока(Выборка.Код)); 
        ДанныеОрганизации.Вставить("Name",  Строка(Выборка.Наименование));
        ДанныеОрганизации.Вставить("INN",   Строка(Выборка.ИНН));
        ДанныеОрганизации.Вставить("KPP",   Строка(Выборка.КПП));
        
        МассивОрганизаций.Добавить(ДанныеОрганизации);
    КонецЦикла;
    
    // Сериализация
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, МассивОрганизаций);
    СтрокаДляОтвета = ЗаписьJSON.Закрыть();
    
    // Установка тела. Важно указать кодировку явно.
    Ответ.УстановитьТелоИзСтроки(СтрокаДляОтвета, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
    
    Возврат Ответ;
    
КонецФункции

Резюме

Чтобы HTTP-сервис работал корректно:

  1. Не пытайтесь авторизовать пользователя внутри кода 1С. Используйте параметры HTTPСоединение на стороне клиента.
  2. Если используете Apache и получаете запросы авторизации несмотря на переданные пароли — проверьте наличие директивы SetEnvIf.
  3. Если получаете ошибку 500 при успешной записи данных — проверьте Журнал регистрации. Скорее всего, проблема в "Безопасном режиме" расширения или попытке вывода сообщений пользователю в серверном коде.
← На главную