Как исправить ошибку "mark/reset not supported" в мобильном приложении 1С при вызове Web-сервиса?

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

При разработке мобильных приложений на платформе 1С программисты часто сталкиваются с ситуацией, когда небольшие пакеты данных передаются через Web-сервисы без проблем, но при увеличении объема передаваемой информации (например, при передаче файлов или больших структур ValueStorage) возникает ошибка: «Ошибка работы с Интернет: mark/reset not supported». Эта проблема специфична для устройств под управлением ОС Android и имеет под собой глубокие технические корни, связанные с реализацией сетевого стека Java.

В данной статье мы подробно разберем, почему возникает эта ошибка, проанализируем механизмы работы мобильной платформы и рассмотрим несколько способов решения проблемы — от простого обновления платформы до архитектурных изменений в коде обмена данными.

Разбор технической причины возникновения ошибки

Давайте выясним причину возникновения исключения на уровне операционной системы. Ошибка mark/reset not supported является типичным исключением java.io.IOException. Она возникает в те моменты, когда сетевая библиотека Android пытается выполнить метод reset() для потока данных (InputStream), который не поддерживает установку меток или если размер данных превысил выделенный буфер.

Рассмотрим ситуацию подробнее: когда мобильное приложение 1С вызывает операцию Web-сервиса, оно формирует HTTP-запрос. Если на сервере (например, Apache или IIS) включена авторизация (особенно NTLM или Digest), происходит «рукопожатие»:

  1. Клиент отправляет запрос с данными.
  2. Сервер отвечает кодом 401 Unauthorized, предлагая авторизоваться.
  3. Клиент должен отправить тот же запрос повторно, но уже с заголовком авторизации.

Чтобы отправить запрос повторно, системе нужно «отмотать» поток данных к началу. Если объем данных велик и они не поместились в оперативный буфер, метод reset() выдает ошибку, так как поток уже «ушел» вперед и вернуться к началу невозможно. Именно это мы и видим в сообщении об ошибке.

Решение 1: Обновление мобильной платформы (Основной способ)

Проанализируем ситуацию с версиями платформы. Данная проблема была официально признана компанией 1С как баг (ошибка №10204781). Она была связана с некорректной работой внутреннего механизма повтора HTTP-запросов в мобильном клиенте именно для ОС Android.

Вариант исправления: необходимо обновить мобильную платформу. Ошибка была исправлена, начиная с версии 8.3.12.74. Если вы используете более ранние версии (например, 8.3.12.67, как в примере автора темы), вы неизбежно будете сталкиваться с этим ограничением при передаче данных объемом более 60-80 Кб.

Проверим работоспособность на примере кода, который часто используется для тестирования стабильности соединения:


Прокси = СформироватьПроксиНаКлиенте();
Если Прокси = Неопределено Тогда 
    Возврат "Ошибка инициализации прокси"; 
КонецЕсли;

Стр = "";
ГСЧ = Новый ГенераторСлучайныхЧисел;
Пока СтрДлина(Стр) < 80000 Цикл
    Стр = Стр + ГСЧ.СлучайноеЧисло(1000, 1000000) + Символы.ПС;
КонецЦикла;

Дд = ПолучитьДвоичныеДанныеИзСтроки(Стр);
ДанныеДляПередачи = Новый ХранилищеЗначения(Дд);

Попытка
    Ответ = Прокси.GetData(ДанныеДляПередачи);
    Сообщить("Успешная передача: " + Ответ);
Исключение
    Сообщить("Произошла ошибка: " + ОписаниеОшибки());
КонецПопытки;

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

Решение 2: Смена способа авторизации на Web-сервере

Если по каким-то причинам обновить платформу на всех устройствах пользователей невозможно, мы можем попытаться обойти проблему на уровне настроек инфраструктуры. Рассмотрим работу с Web-сервером Apache.

Как мы выяснили, ошибка часто провоцируется повторным запросом из-за авторизации 401. Чтобы этого избежать, можно использовать Basic-авторизацию и настроить клиент так, чтобы он отправлял учетные данные сразу, не дожидаясь запроса от сервера. В некоторых случаях помогает переход на анонимный доступ (если это допустимо политикой безопасности), так как в этом случае поток данных передается один раз и потребность в mark/reset отпадает.

Решение 3: Оптимизация передачи данных (Чанкование)

Разберем еще один надежный метод, который помогает при работе в нестабильных мобильных сетях и обходит ограничения буферов — разделение больших данных на части (чанки). Вместо того чтобы передавать один объект ХранилищеЗначения размером 20 Мб, мы можем реализовать алгоритм передачи по частям.

Пошаговый алгоритм:

  1. Разбиваем двоичные данные на клиенте на пакеты (например, по 64 Кб).
  2. Передаем каждый пакет отдельным вызовом метода Web-сервиса, добавляя идентификатор транзакции и номер пакета.
  3. На стороне сервера собираем пакеты во временном файле или регистре сведений.
  4. После передачи всех частей инициируем на сервере сборку финального объекта.

Этот метод не только решает проблему mark/reset not supported, но и делает обмен данными гораздо более устойчивым к разрывам связи, так как при сбое не нужно переотправлять все 20 Мб — достаточно повторить отправку одного маленького пакета.

Решение 4: Использование HTTP-запросов вместо Web-сервисов

Проанализируем альтернативный транспорт. В 1С помимо объектов WSПрокси можно использовать объект HTTPСоединение. При передаче данных через HTTPЗапрос и метод ОтправитьДляОбработки() (POST-запрос), платформа иногда использует другие механизмы работы с потоками, которые могут быть более устойчивы к данной ошибке в старых версиях Android.

Пример использования HTTPСоединение для передачи данных:


Соединение = Новый HTTPСоединение("myserver.ru", , Логин, Пароль);
Заголовок = Новый Соответствие();
Заголовок.Вставить("Content-Type", "application/octet-stream");

Запрос = Новый HTTPЗапрос("/v1/data/upload", Заголовок);
Запрос.УстановитьТелоИзДвоичныхДанных(Дд);

Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 200 Тогда
    Сообщить("Данные успешно отправлены");
КонецЕсли;

Важное замечание о типе данных ValueStorage

Стоит помнить, что при передаче ХранилищеЗначения через параметры Web-сервиса, 1С выполняет автоматическую сериализацию в формат Base64. Это увеличивает объем данных примерно на 33%. Если ваш файл весит 15 Мб, то по сети фактически будет передаваться около 20 Мб. При достижении определенных лимитов в памяти устройства Android это может приводить к непредсказуемому поведению сетевого стека. Рассмотрим возможность передачи чистых двоичных данных (Binary Data) или использование сжатия (Zip), чтобы минимизировать нагрузку на канал связи.

Итоги

Подводя итог, мы можем выделить следующие рекомендации для устранения ошибки mark/reset not supported:

Соблюдение этих рекомендаций позволит вам создавать стабильные мобильные приложения, способные обмениваться большими объемами данных без ошибок сетевого взаимодействия.

← На главную