При разработке HTTP-сервисов на платформе 1С:Предприятие 8.3 программисты часто сталкиваются со специфическим поведением платформы и веб-серверов. Две самые распространенные проблемы при передаче текстовых данных на внешние устройства — это внезапное автоматическое кодирование текста в формат Base64 и подмена успешного статус-кода 200 OK на код 206 Partial Content. В этой статье мы подробно разберем природу этих явлений и рассмотрим надежные способы их устранения.
Рассмотрим ситуацию: вам необходимо передать простой текстовый файл (например, список URL-адресов, конфигурационный файл или набор команд для микроконтроллера) на внешнее «умное» или «тупое» устройство. Вы используете стандартный метод УстановитьТелоИзСтроки() объекта HTTPСервисОтвет, но принимающая сторона вместо обычного текста получает строку в формате Base64.
Выясним причину этого поведения платформы:
Платформа 1С:Предприятие при отправке ответа через HTTPСервисОтвет пытается автоматически определить формат данных. Она делает это на основе анализа заголовка Content-Type и типа передаваемых данных. Логика платформы выглядит следующим образом:
application/octet-stream, application/x-url или любой другой нестандартный подтип семейства application), 1С считает тело ответа двоичным.УстановитьТелоИзСтроки(), платформа принудительно кодирует строку в Base64. Это сделано для того, чтобы защитить потенциально бинарные данные от искажения спецсимволов при передаче по сети.УстановитьИмяФайлаТела(): 1С определяет MIME-тип на основе расширения отправляемого файла. Если расширение не сопоставлено с текстовым типом, файл будет передан как Base64.Давайте разберем два эффективных способа решения этой проблемы.
Самый простой способ избежать Base64-кодирования — явно указать платформе, что передаваемые данные являются текстом. Для этого нужно установить текстовый заголовок Content-Type. Вместо бинарных типов вроде application/x-url следует использовать стандартные текстовые MIME-типы:
text/plain — для обычного неструктурированного текста;text/uri-list — стандартный MIME-тип для передачи списков ссылок;text/x-url — если устройство требует именно этот формат.Посмотрим на пример кода, где мы явно задаем текстовый формат в заголовках:
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "text/plain; charset=utf-8");
ТекстОтвета = "строка1" + Символы.ПС + "строка2" + Символы.ПС + "строка3";
Ответ.УстановитьТелоИзСтроки(ТекстОтвета, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Возврат Ответ;
При использовании текстового MIME-типа платформа 1С передаст строку «как есть» в открытом виде без применения Base64.
Что делать, если принимающее устройство жестко требует заголовок application/x-url или application/octet-stream, но при этом абсолютно не умеет декодировать Base64? В таком случае использование метода УстановитьТелоИзСтроки() нам не подходит.
Решением является самостоятельное преобразование строки в двоичные данные перед отправкой. Мы преобразуем текст в массив байтов в нужной кодировке и передаем его через метод УстановитьТелоИзДвоичныхДанных(). В этом случае 1С запишет байты в поток «как есть» и не будет пытаться применить Base64, независимо от того, какой Content-Type вы укажете.
Проанализируем пример реализации этого метода:
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "application/x-url");
ТекстОтвета = "строка1" + Символы.ПС + "строка2";
// Преобразуем строку в двоичные данные.
// Третий параметр "Ложь" отключает запись BOM (Byte Order Mark) в начало файла
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(ТекстОтвета, КодировкаТекста.UTF8, Ложь);
Ответ.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанные);
Возврат Ответ;
Этот подход гарантирует 100% контроль над отправляемыми байтами и позволяет обойти любые автоматические алгоритмы кодирования платформы 1С.
---
Теперь разберем вторую проблему: вы настроили HTTP-сервис, жестко указали в коде код состояния 200: Ответ = Новый HTTPСервисОтвет(200) или Ответ.КодСостояния = 200, но клиентское устройство все равно получает ответ со статусом 206 (Partial Content). При этом в заголовках ответа появляются параметры Content-Range.
Выясним причину этого странного поведения:
Важно понимать: платформа 1С сама по себе никогда принудительно не меняет код состояния 200 на 206. Подмена статуса происходит на уровне веб-сервера (IIS, Apache или Nginx), на котором опубликована информационная база 1С. Схема взаимодействия выглядит следующим образом:
Range: bytes=0- или Range: bytes=0-911. Клиент делает это для проверки поддержки дозагрузки файлов или скачивания данных частями.Range), веб-сервер берет полный ответ от 1С, вырезает из него указанный диапазон байтов, принудительно меняет код состояния с 200 на 206 Partial Content, добавляет заголовок Content-Range и отправляет этот усеченный пакет клиенту.Попытки прописать статус 200 в коде 1С здесь бессильны, так как веб-сервер модифицирует ответ уже на выходе из приложения. Давайте рассмотрим способы борьбы с этим поведением.
Мы можем явно сообщить веб-серверу и клиенту, что наш HTTP-сервис не поддерживает отдачу контента частями. Для этого в заголовки ответа 1С необходимо добавить заголовок Accept-Ranges со значением none:
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Accept-Ranges", "none");
Ответ.Заголовки.Вставить("Content-Type", "text/plain");
Ответ.УстановитьТелоИзСтроки("Ваш текст");
Возврат Ответ;
Увидев заголовок Accept-Ranges: none, корректно написанный клиент должен проигнорировать заголовок Range и запросить весь файл целиком, что приведет к возврату стандартного статуса 200 OK.
Если устройство невозможно перепрограммировать, и оно принудительно шлет заголовок Range, а веб-сервер Apache упорно переводит ответы в статус 206, мы можем заставить Apache полностью игнорировать этот заголовок для публикации 1С.
Для этого откройте конфигурационный файл httpd.conf вашего сервера Apache или найдите файл .htaccess в каталоге, куда выполнена публикация базы 1С. Добавьте в него следующую директиву:
<IfModule mod_headers.c>
RequestHeader unset Range
</IfModule>
Также можно полностью отключить поддержку диапазонов для всего сервера или конкретного каталога с помощью директивы:
MaxRanges none
После сохранения конфигурации и перезапуска службы Apache веб-сервер перестанет видеть заголовок Range во входящих запросах и будет отдавать стандартный ответ 200 OK с полным телом сообщения.
В веб-сервере IIS (Internet Information Services) решить эту проблему можно с помощью официального модуля расширения URL Rewrite. Сделайте следующие шаги:
HTTP_RANGE (установите ее значение пустым).Очистка переменной HTTP_RANGE приведет к тому, что IIS обработает запрос как обычный GET-запрос без требования частичного контента и вернет клиенту статус 200 OK.
Очень часто перед веб-сервером IIS или Apache устанавливают производительный прокси-сервер Nginx. Если в вашей инфраструктуре используется Nginx, решить проблему со статусом 206 можно в один клик прямо в его конфигурационном файле nginx.conf.
Найдите блок location, отвечающий за перенаправление запросов к вашей публикации 1С, и добавьте туда строку, сбрасывающую заголовок Range:
location /your_1c_publication/ {
proxy_pass http://backend_server;
proxy_set_header Range "";
}
Это действие полностью сотрет заголовок Range из запроса клиента перед передачей его на бэкэнд (IIS или Apache). Веб-сервер приложения получит чистый запрос и вернет корректный ответ со статусом 200 OK.
---
Мы детально изучили две важные проблемы при работе с HTTP-сервисами в 1С:Предприятии 8.3.
Для предотвращения нежелательного кодирования данных в Base64 всегда контролируйте заголовок Content-Type (используйте типы семейства text) или передавайте данные напрямую в бинарном формате через метод УстановитьТелоИзДвоичныхДанных().
Для борьбы с нежелательным статусом 206 Partial Content используйте отправку заголовка Accept-Ranges: none из 1С либо настройте фильтрацию входящего заголовка Range на уровне вашего веб-сервера (Apache, IIS или Nginx).