HTTPСервисЗапрос.ПолучитьТелоКакДвоичныеДанные

Методы · GetBodyAsBinaryData

Возвращает тело запроса в виде двоичных данных.

Синтаксис

ПолучитьТелоКакДвоичныеДанные()
Полное описание, параметры и ограничения

HTTPСервисЗапрос.ПолучитьТелоКакДвоичныеДанные (HTTPServiceRequest.GetBodyAsBinaryData)

HTTPСервисЗапрос (HTTPServiceRequest)

ПолучитьТелоКакДвоичныеДанные (GetBodyAsBinaryData)

Доступен, начиная с версии 8.3.5.

Синтаксис:
ПолучитьТелоКакДвоичныеДанные()
Возвращаемое значение:
Тип: ДвоичныеДанные.

Описание:

Возвращает тело запроса в виде двоичных данных.

Доступность:

Сервер, толстый клиент.

Использование в версии:

Доступен, начиная с версии 8.3.5.

Методическая информация

Практические примеры

Принять свой настоящий POST в HTTP-сервис1С: маршрут, заголовки, строка, байты, поток и файл ответа

HTTPСервисЗапрос поступает от самой платформы в реальный обработчик опубликованного собственного сервиса, а не конструируется фиктивно. Четыре конкретных запроса проверяют route/query/header/UTF8-body, последний возвращает только свежесозданный собственный файл.

Где и как запускать

Полный модуль собственного HTTP-сервиса УчебныйПрием85 новой пустой УчебныйHTTP85, nativehandlerPOST Принять85(Запрос). Полный клиентский модуль и fixtureschema включены, production и реальная сеть не используются.

Подготовка

  1. Только отдельная собственная Windows VM и новая пустая конфигурация УчебныйHTTP858.5.1.1343. Русский язык, совместимость Не использовать, управляемый интерфейс. Нет предметных объектов, расширений, фона и рабочей базы. Автор не публиковал сервис, не отправлял HTTP и не создавал файлы. OwnHTTPSource здесь — полные тексты для вашей ручной изолированной проверки.

  2. Вручную создайте единственного пользователя HttpLab85_ с добавленным новым ненулевым каноническим UUID, разрешите ему стандартную аутентификацию, задайте только свой новый учебный пароль. Назначьте права администрирования пользователей/данных, использования своего HTTP-сервиса и чтения нужных метаданных. Нет производства/персональных данных; код не создает пользователя и не меняет роли/пароль.

  3. Конфигуратор → Общие → HTTP-сервисы: создайте единственный УчебныйПрием85, КорневойURL guide85. Создайте шаблон СобственнаяКарточка с ШаблонURL /lab/{session}, метод POST, Обработчик Принять85. Вставьте весь основной модуль в модуль этого HTTP-сервиса. Не помещайте его в клиентскую форму/общий модуль: реальный Запрос передает платформа этому обработчику.

  4. В своей VM вручную опубликуйте ТОЛЬКО эту новую базу под именем guide85 на отдельном IIS/Apache binding127.0.0.1:18086. Публикуйте только свой HTTP-сервис, не anonymous доступ/production/OData, без redirects/proxy/public listener. Выберите стандартную Basic-аутентификацию собственного тестового пользователя. Configure web-server request body limit4096 байт до попадания в1С; header-limit умеренный, Transfer-Encoding/chunked для этого собственного опыта отклоняется в обработчике.

  5. Путь собственного endpoint: http://127.0.0.1:18086/guide85/hs/guide85/lab/<реальныйUUIDпользователяБазы>?mode=text. NativeБазовыйURL может быть относительной частью /guide85/hs/guide85 либо полным этим loopbackURL; обработчик принимает только эти две явно подготовленные формы. ОтносительныйURL должен быть /lab/UUID безquery. Если ваша публикация выдает иной формат, сначала проверьте его штатно на своем стенде, а не расширяйте guard до любого URL.

  6. В той же базе создайте свою внешнюю обработку УчебныйКлиентПриема85 с одной управляемой формой. Строки Метка85 длиной36, Имя85 длиной100, Пароль85 длиной100, Подтверждение85 длиной100, Статус85 длиной0; булево Начат85. Метка/имя/статус/флаг только для просмотра, пароль защищенно отображается. Назначьте ПриСозданииНаСервере и команду Выполнить85→Выполнить85, вставьте полный поддерживающий модуль формы.

  7. Метка и имя берутся из реального своего текущего пользователя, не задаются произвольным UUID. Введите только пароль собственной тестовой учетной записи. Сначала оставьте фразу пустой: запросов не должно быть. После проверки VM введите СВОЯ ПУБЛИКАЦИЯ127.0.0.1 и один раз нажмите команду. Положительный путь — thin/thick managed этого собственного стенда; не обещается работа web/mobile/внешнейпубликации.

  8. Клиент отправит четыре небольших POST: mode=text, bytes, stream, file, всегда свой UTF-8 текст UUID|Книга|3|250, отдельные Content-Type/X-Guide-Session и реальный Content-Length, сформированный HTTP транспортом. Обработчик сравнит авторизованного пользователя, URLsession, querymode и реальные байты. Никакой arbitraryfilepath/открытый echo/произвольныйSQL тут не принимаются.

  9. В file-ветви сервер1С создаст ровно один новый небольшой временный файл только собственного ответа. GetTempFileName не создает его сам; существующее имя не перезаписывается. После SetBodyFilename нельзя удалять этот файл до фактического формирования ответа платформой. Путь не выводится клиенту/логам. Это не backup/archive, и автор таких файлов не создавал.

  10. По установленной справке свежий серверный временный файл платформой очищается после завершения вызова с отложенным сроком; урок не выдает эту будущую очистку за уже проверенную. Не устраивайте нагрузочный бесконечный тест: запустите только один свой опыт. Закрытие формы не доказывает отсутствие файла при неизвестном HTTP-результате, catch ничего автоматически не удаляет.

Функция Принять85(Запрос)
    Попытка
        Пользователь = ПроверитьСвойHTTPПользователь85();
        Метка = Строка(Пользователь.УникальныйИдентификатор);
        Если ТипЗнч(Запрос) <> Тип("HTTPСервисЗапрос") Или Запрос.HTTPМетод <> "POST" Тогда
            Возврат Отказ85(405);
        КонецЕсли;
        База = Запрос.БазовыйURL;
        Если База <> "/guide85/hs/guide85" И База <> "http://127.0.0.1:18086/guide85/hs/guide85" Тогда
            Возврат Отказ85(400);
        КонецЕсли;
        Если НайтиЗаголовок85(Запрос.Заголовки, "Host") <> "127.0.0.1:18086"
            Или НайтиЗаголовок85(Запрос.Заголовки, "X-Guide-Session") <> Метка
            Или НайтиЗаголовок85(Запрос.Заголовки, "Content-Type") <> "text/plain; charset=utf-8"
            Или НайтиЗаголовок85(Запрос.Заголовки, "Transfer-Encoding") <> Неопределено Тогда
            Возврат Отказ85(400);
        КонецЕсли;
        Если Запрос.ПараметрыURL.Количество() <> 1 Или Запрос.ПараметрыURL.Получить("session") <> Метка
            Или Запрос.ОтносительныйURL <> "/lab/" + Метка Тогда
            Возврат Отказ85(404);
        КонецЕсли;
        Если Запрос.ПараметрыЗапроса.Количество() <> 1 Тогда
            Возврат Отказ85(400);
        КонецЕсли;
        Режим = Запрос.ПараметрыЗапроса.Получить("mode");
        Если Режим <> "text" И Режим <> "bytes" И Режим <> "stream" И Режим <> "file" Тогда
            Возврат Отказ85(400);
        КонецЕсли;
        ОжидаемыйТекст = Метка + "|Книга|3|250";
        ОжидаемыеБайты = ПолучитьДвоичныеДанныеИзСтроки(ОжидаемыйТекст, "UTF-8", Ложь);
        СтрокаДлины = НайтиЗаголовок85(Запрос.Заголовки, "Content-Length");
        Если ТипЗнч(СтрокаДлины) <> Тип("Строка") Тогда
            Возврат Отказ85(411);
        КонецЕсли;
        Длина = Число(СтрокаДлины);
        Если Строка(Длина) <> СтрокаДлины Или Длина <> ОжидаемыеБайты.Размер() Или Длина > 4096 Тогда
            Возврат Отказ85(413);
        КонецЕсли;
        Если Режим = "text" Тогда
            Текст = Запрос.ПолучитьТелоКакСтроку("UTF-8");
            Если Текст <> ОжидаемыйТекст Тогда
                Возврат Отказ85(400);
            КонецЕсли;
        ИначеЕсли Режим = "stream" Тогда
            ПроверитьСвойПоток85(Запрос.ПолучитьТелоКакПоток(), ОжидаемыеБайты);
        Иначе
            Байты = Запрос.ПолучитьТелоКакДвоичныеДанные();
            Если Байты.Размер() <> Длина Или Base64Строка(Байты) <> Base64Строка(ОжидаемыеБайты) Тогда
                Возврат Отказ85(400);
            КонецЕсли;
        КонецЕсли;
        Заголовки = Новый Соответствие;
        Заголовки.Вставить("Content-Type", "text/plain; charset=utf-8");
        Заголовки.Вставить("X-Guide-Session", Метка);
        Ответ = Новый HTTPСервисОтвет(200, , Заголовки);
        ТекстОтвета = Метка + "|" + Режим + "|Книга|3|250";
        Если Режим = "file" Тогда
            ИмяСвоегоФайла = ПолучитьИмяВременногоФайла("guide85.txt");
            СвойФайл = Новый Файл(ИмяСвоегоФайла);
            Если СвойФайл.Существует() Тогда
                ВызватьИсключение "Новое собственное имя уже занято; ничего не перезаписывается";
            КонецЕсли;
            СвоёТело = ПолучитьДвоичныеДанныеИзСтроки(ТекстОтвета, "UTF-8", Ложь);
            СвоёТело.Записать(ИмяСвоегоФайла);
            Если Не СвойФайл.Существует() Или СвойФайл.Размер() <> СвоёТело.Размер() Тогда
                ВызватьИсключение "Свой небольшой файл ответа не подтвержден";
            КонецЕсли;
            Ответ.УстановитьИмяФайлаТела(ИмяСвоегоФайла);
            Если Ответ.ПолучитьИмяФайлаТела() <> ИмяСвоегоФайла Тогда
                ВызватьИсключение "В ответе не тот собственный файл";
            КонецЕсли;
        Иначе
            Ответ.УстановитьТелоИзСтроки(ТекстОтвета, "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
        КонецЕсли;
        Возврат Ответ;
    Исключение
        Возврат Отказ85(400);
    КонецПопытки;
КонецФункции

Функция НайтиЗаголовок85(Заголовки, Имя)
    Значение = Неопределено;
    Найден = Ложь;
    Для Каждого Пара Из Заголовки Цикл
        Если НРег(Пара.Ключ) = НРег(Имя) Тогда
            Если Найден Тогда
                ВызватьИсключение "Неоднозначный собственный заголовок";
            КонецЕсли;
            Найден = Истина;
            Значение = Пара.Значение;
        КонецЕсли;
    КонецЦикла;
    Возврат Значение;
КонецФункции

Процедура ПроверитьСвойПоток85(ПотокТела, ОжидаемыеБайты)
    ОжидаемыйБуфер = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(ОжидаемыеБайты);
    Буфер = Новый БуферДвоичныхДанных(128);
    Смещение = 0;
    Попытка
        Если Не ПотокТела.ДоступноЧтение Тогда
            ВызватьИсключение "Поток собственного тела не поддерживает чтение";
        КонецЕсли;
        Пока Истина Цикл
            Прочитано = ПотокТела.Прочитать(Буфер, 0, 128);
            Если Прочитано = 0 Тогда
                Прервать;
            КонецЕсли;
            Если Смещение + Прочитано > ОжидаемыеБайты.Размер() Тогда
                ВызватьИсключение "Собственное тело превышает известный размер";
            КонецЕсли;
            Для Индекс = 0 По Прочитано - 1 Цикл
                Если Буфер[Индекс] <> ОжидаемыйБуфер[Смещение + Индекс] Тогда
                    ВызватьИсключение "Байт собственного тела не совпал";
                КонецЕсли;
            КонецЦикла;
            Смещение = Смещение + Прочитано;
        КонецЦикла;
        Если Смещение <> ОжидаемыеБайты.Размер() Тогда
            ВызватьИсключение "Собственное тело пришло не полностью";
        КонецЕсли;
    Исключение
        ПотокТела.Закрыть();
        ВызватьИсключение;
    КонецПопытки;
    ПотокТела.Закрыть();
КонецПроцедуры

Функция Отказ85(Код)
    Ответ = Новый HTTPСервисОтвет(Код);
    Ответ.УстановитьТелоИзСтроки("Учебный запрос отклонен", "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
    Возврат Ответ;
КонецФункции

Функция ПроверитьСвойHTTPПользователь85()
    ПроверитьСвойПустойСтенд();
    Если ПривилегированныйРежим() Тогда
        ВызватьИсключение "Входной привилегированный режим не допускается";
    КонецЕсли;
    Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
    Текущий = ПользователиИнформационнойБазы.ТекущийПользователь();
    Если Пользователи.Количество() <> 1 Или Текущий = Неопределено
        Или Пользователи[0].УникальныйИдентификатор <> Текущий.УникальныйИдентификатор
        Или Лев(Текущий.Имя, СтрДлина("HttpLab85_")) <> "HttpLab85_" Тогда
        ВызватьИсключение "Нужен единственный собственный внутренний HTTP-пользователь";
    КонецЕсли;
    UUIDМетки = Новый УникальныйИдентификатор(Сред(Текущий.Имя, СтрДлина("HttpLab85_") + 1));
    Если Текущий.Имя <> "HttpLab85_" + Строка(UUIDМетки)
        Или UUIDМетки = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000") Тогда
        ВызватьИсключение "Учебный UUID-пользователь не подтвержден";
    КонецЕсли;
    Если Метаданные.HTTPСервисы.Количество() <> 1 Или Метаданные.HTTPСервисы.Найти("УчебныйПрием85") = Неопределено Тогда
        ВызватьИсключение "В своей базе нужен только собственный HTTP-сервис УчебныйПрием85";
    КонецЕсли;
    Возврат Текущий;
КонецФункции

Процедура ПроверитьСвойПустойСтенд()
    Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
        ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
    КонецЕсли;
    Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
        ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
    КонецЕсли;
    Источники = Новый Массив;
    Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
    Для Каждого Источник Из Источники Цикл
        Расширения = РасширенияКонфигурации.Получить(, Источник);
        Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
            ВызватьИсключение "Native список расширений должен иметь тип Массив";
        КонецЕсли;
        Если Расширения.Количество() <> 0 Тогда
            ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
        КонецЕсли;
    КонецЦикла;
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
    КонецЕсли;
КонецПроцедуры
Полный модуль своей управляемой формы: четыре настоящих POST в свою публикацию

Обработка собственной CF УчебныйHTTP85: полный модуль управляемой формы

Собственная управляемая форма desktop клиента, четыре POST только в свою новую публикацию 127.0.0.1:18086; здесь запросы/публикация не выполняются.

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Пользователь = ПроверитьСвойHTTPПользователь85();
    Метка85 = Строка(Пользователь.УникальныйИдентификатор);
    Имя85 = Пользователь.Имя;
    Пароль85 = "";
    Подтверждение85 = "";
    Начат85 = Ложь;
    Статус85 = "Своя loopback-публикация пока не проверена";
КонецПроцедуры

&НаКлиенте
Процедура Выполнить85(Команда)
    Если Начат85 Или Подтверждение85 <> "СВОЯ ПУБЛИКАЦИЯ127.0.0.1" Или Не ЗначениеЗаполнено(Пароль85) Тогда
        ВызватьИсключение "Нужен свой пароль своей тестовой учетной записи и один явный опыт";
    КонецЕсли;
    ПроверитьСеанс85();
    Начат85 = Истина;
    Попытка
        Соединение = Новый HTTPСоединение("127.0.0.1", 18086, Имя85, Пароль85, Новый ИнтернетПрокси(Ложь), 5, Неопределено, Ложь);
        Режимы = СтрРазделить("text,bytes,stream,file", ",");
        Для Каждого Режим Из Режимы Цикл
            Заголовки = Новый Соответствие;
            Заголовки.Вставить("Content-Type", "text/plain; charset=utf-8");
            Заголовки.Вставить("X-Guide-Session", Метка85);
            Запрос = Новый HTTPЗапрос("/guide85/hs/guide85/lab/" + Метка85 + "?mode=" + Режим, Заголовки);
            Запрос.УстановитьТелоИзСтроки(Метка85 + "|Книга|3|250", "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
            Ответ = Соединение.ОтправитьДляОбработки(Запрос);
            Если Ответ.КодСостояния <> 200 Или Ответ.Заголовки.Получить("X-Guide-Session") <> Метка85
                Или Ответ.ПолучитьТелоКакСтроку("UTF-8") <> Метка85 + "|" + Режим + "|Книга|3|250" Тогда
                ВызватьИсключение "Полный собственный ответ режима не совпал";
            КонецЕсли;
        КонецЦикла;
        Пароль85 = "";
        Статус85 = "Все четыре режима источника собственного POST и ответ из собственного файла проверены";
    Исключение
        Пароль85 = "";
        Статус85 = "Запрос не подтвержден. Никакие автоматические повторы или удаления файла не выполнялись";
        ВызватьИсключение "Проверьте только собственную публикацию; пароль/чужое тело в лог не выводятся";
    КонецПопытки;
КонецПроцедуры

&НаСервере
Процедура ПроверитьСеанс85()
    Пользователь = ПроверитьСвойHTTPПользователь85();
    Если Метка85 <> Строка(Пользователь.УникальныйИдентификатор) Или Имя85 <> Пользователь.Имя Тогда
        ВызватьИсключение "Показанный собственный пользователь изменен";
    КонецЕсли;
КонецПроцедуры

&НаСервере
Функция ПроверитьСвойHTTPПользователь85()
    ПроверитьСвойПустойСтенд();
    Если ПривилегированныйРежим() Тогда
        ВызватьИсключение "Входной привилегированный режим не допускается";
    КонецЕсли;
    Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
    Текущий = ПользователиИнформационнойБазы.ТекущийПользователь();
    Если Пользователи.Количество() <> 1 Или Текущий = Неопределено
        Или Пользователи[0].УникальныйИдентификатор <> Текущий.УникальныйИдентификатор
        Или Лев(Текущий.Имя, СтрДлина("HttpLab85_")) <> "HttpLab85_" Тогда
        ВызватьИсключение "Нужен единственный собственный внутренний HTTP-пользователь";
    КонецЕсли;
    UUIDМетки = Новый УникальныйИдентификатор(Сред(Текущий.Имя, СтрДлина("HttpLab85_") + 1));
    Если Текущий.Имя <> "HttpLab85_" + Строка(UUIDМетки)
        Или UUIDМетки = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000") Тогда
        ВызватьИсключение "Учебный UUID-пользователь не подтвержден";
    КонецЕсли;
    Если Метаданные.HTTPСервисы.Количество() <> 1 Или Метаданные.HTTPСервисы.Найти("УчебныйПрием85") = Неопределено Тогда
        ВызватьИсключение "В своей базе нужен только собственный HTTP-сервис УчебныйПрием85";
    КонецЕсли;
    Возврат Текущий;
КонецФункции

&НаСервере
Процедура ПроверитьСвойПустойСтенд()
    Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
        ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
    КонецЕсли;
    Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
        ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
    КонецЕсли;
    Источники = Новый Массив;
    Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
    Для Каждого Источник Из Источники Цикл
        Расширения = РасширенияКонфигурации.Получить(, Источник);
        Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
            ВызватьИсключение "Native список расширений должен иметь тип Массив";
        КонецЕсли;
        Если Расширения.Количество() <> 0 Тогда
            ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
        КонецЕсли;
    КонецЦикла;
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
    КонецЕсли;
КонецПроцедуры

Разбор по шагам

  1. В реальную Принять85(Запрос) платформа передает HTTPСервисЗапрос. Конструктора у этого типа нет. Guard собственной конфигурации и единственногоUUIDпользователя выполняется до чтения входного тела; nativeRequest.HTTPМетод обязан бытьPOST.

  2. ReadonlyБазовыйURL проверяется только на две подготовленные формы своего loopbackendpoint, Host на127.0.0.1:18086, headerUUID на реальный UUID авторизованного пользователя. Заголовки — ФиксированноеСоответствие, не изменяемый список. Имена header сравниваются без учета регистра и дубликат не принимается.

  3. ReadonlyПараметрыURL содержат только session из шаблона /lab/{session}, а ПараметрыЗапроса — только mode изquery. Это разные источники. ОтносительныйURL должен совпасть со своим путем; дополнительный route/query не принимается.

  4. Content-Type=text/plain;charset=utf-8 и Content-Length обязательны для своего небольшого известного тела. Размер сравнивается с заранее сформированными ожидаемыми UTF-8-байтами, не с количеством символов русского текста. Web-server ограничение4096 должно действовать ДО handler: одна проверка header не защищает от уже принятого огромного/misdeclared тела.

  5. mode=text вызывает ПолучитьТелоКакСтроку("UTF-8") и сравнивает весь собственный текст. Кодировка указана явно; установка body в клиенте и Content-Type заголовок — разные операции.

  6. mode=bytes получает настоящие ДвоичныеДанные, сравнивает реальный размер и точные bytes черезBase64 только в памяти. Base64 не используется как шифрование/авторизация и не выводится в лог.

  7. mode=stream использует настоящий nativeПоток тела, один буфер128 и loop по фактически прочитанному числу байтов. Читаются только фактические байты, короткие чтения не выдаются заEOF. Размер() потока не вызывается, seekability не предполагается; превышение/обрыв/несовпадение отказаны. Поток закрывается и на успехе, и на исключении.

  8. Положительный Ответ создается HTTPСервисОтвет(200,,headers), текст включает свой UUID/реальныйmode/учебную карточку. Обработчик обязан вернуть этот объект платформе; создание объекта само по себе не отправляет сетевой ответ.

  9. mode=file записывает только собственное небольшое тело в новое GetTempFileName имя, проверяет отсутствие до записи, existence/размер после. SetBodyFilename выбирает источник; GetBodyFilename сверяет точно этот собственный путь. Чтение платформой будет позже, поэтому раннего удаления/закрытия файла вместо ответа нет.

  10. Поддерживающий клиент передает четыре настоящих HTTPЗапроса в свое публикационное1СHTTPendpoint, не mock объектаЗапрос. Каждый ответ требует200, собственный headerUUID и полный текст выбранногоmode, в том числе file-body. Пароль очищается после результата/исключения и не логируется.

  11. При отказе/ошибке handler возвращает только стандартный код405/404/411/413/400 и постоянный безопасный текст. Содержимое неизвестного запроса, пароль, серверные пути и stacktrace не отражаются наружу. Объекты базы не пишутся; файлы/запросы автором реально не выполнялись.

Как проверить результат

  1. У своего правильного запроса HTTPMethod=POST, только route session и querymode, exactHost/headerUUID и knownbyte length. Неверный метод/path/UUID/добавочныйquery/header/type дает отказ до работы с body.

  2. text/bytes/stream должны получить полностью одинаковые ownUTF8-байты Книги; обрыв, неверный BOM/кодировка/длина/содержимое не подтверждаются частичным успехом.

  3. Stream branch закрывает поток при обоих исходах, не требуетseek/Размер(). Нулевое чтение —конец, короткое положительное чтение продолжается. Фактический итог обязан совпасть с ожидаемым размером.

  4. File branch не перезаписывает существующий файл, точно связывает новый ownfilename сHTTPСервисОтвет и не удаляет его до delayed read. Свежий клиентский fileответ должен содержать тот же свой текст, не path/страницу ошибки.

  5. Клиент дает четыре подтвержденных ответа200 либо конкретный отказ. Повтор commandНачат=true запрещен, password очищается, лог не содержитнеизвестныхbody/credentials/serverpaths.

  6. Конфигурация, права, веб-публикация, requestLimits и реальное delayed file чтение здесь не были развернуты/запущены. Это отдельные ручные проверки только в собственной VM, не доказанные статическими тестами.

Ожидаемый результат

Все свойства/три метода настоящего HTTPСервисЗапрос разобраны в опубликованном своем handler, а file-body источникHTTPСервисОтвет привязан к конкретному новому собственному файлу с учетом delayedread. Четыре полных запроса клиента и критерии отказа/успеха включены.

На что обратить внимание

  1. HTTPСервисЗапрос создается платформой только при входящем запросе собственного опубликованного сервиса; его нельзя заменить НовыйHTTPСервисЗапрос или произвольнойСтруктура. ReadonlyHeaders/URL/query не назначаются.

  2. Собственный UUID в URL/header не является аутентификацией. Требуется реальная проверенная Basic-аутентификация своего внутреннего пользователя и права, плюс выделенная VM/loopback. PlainHTTPBasic недопустимы для production-паролей, а webserverHost/header могут быть подделаны без этой изоляции.

  3. БазовыйURL и ОтносительныйURL — разные части, routeParameters и queryParameters тоже. Handler не склеивает пользовательский путь с именем локального файла. Любой иной публикационный формат требует проверки в своем стенде, не угадывания/расширения до любых сайтов.

  4. Принимающий веб-сервер способен буферизоватьbody еще доhandler. Ограничить Content-Length внутри1С недостаточно против огромного/misdeclared/chunkedrequest; ownIIS/Apache лимит4096 обязателен. Этот урок не универсальный защищенный публичныйAPI.

  5. Поток может отдаватькороткие чтения и не поддерживатьseek/Размер. СравниваютсятолькоПрочитано bytes;конец0 не равен любомукороткому чтению. В программе нет использованиянеинициализированногоконца128байтного буфера.

  6. HTTPСервисОтвет file-source читается приформированииответа платформой, не вSetBodyFilename. Удалениевконцеhandlerсломалобыещеотправляемыйответ. Отложеннуюплатформеннуюочистку/actualfileoutput нужно проверять отдельно; новые резервныекопии/архивы не создаются.

  7. ПриunknownHTTPрезультате file мог бытьсоздан, handler/requestвыполнен. Catch не делает cleanupчужих/широкихкаталогов и не возвращаетrawОшибка. Повторные/нагрузочные вызовы могут создаватьмалые файлы;положительныйопыт ограниченоднимownclientrun.

  8. Server/client/module contexts иnative8.5.1.1343контракты сверяются статически. Подготовительныеmetadata/publication/auth/requestlimitоперации, отправкаHTTP и delayedresponse/filecleanup реальноне выполнялись. RuntimeVerifiedScenarios=0.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.