В процессе разработки на платформе 1С:Предприятие 8.3 многие программисты сталкиваются с загадочной ошибкой: «Ошибка передачи данных между клиентом и сервером. Недопустимый символ XML». Самое удивительное здесь то, что ошибка может возникать при работе с обычными строками, которые, казалось бы, не имеют никакого отношения к XML-файлам. В данной статье мы подробно разберем, почему так происходит, какие символы являются «запрещенными» и как правильно организовать передачу таких данных, чтобы избежать аварийного завершения работы программы.
Для начала проанализируем механизм взаимодействия между тонким (или веб) клиентом и сервером приложений. Рассмотрим ситуацию: когда мы вызываем процедуру с директивой компиляции &НаСервере или передаем данные через параметры формы, платформа выполняет сериализацию объектов. Несмотря на то, что современные веб-технологии часто используют JSON, внутренний протокол обмена управляемых форм 1С (часто называемый GREST) по-прежнему базируется на стандарте XML 1.0.
Это означает, что любое значение (будь то Структура, Массив или простая Строка), которое вы передаете с сервера на клиент или обратно, упаковывается в XML-пакет. И именно здесь кроется ловушка. Стандарт XML 1.0 накладывает жесткие ограничения на символы, которые могут находиться в текстовых узлах.
Согласно спецификации, в XML разрешены только следующие символы из диапазона ASCII 0–31:
Символ(9) — Горизонтальная табуляция;Символ(10) — Перевод строки (LF);Символ(13) — Возврат каретки (CR).Все остальные управляющие символы (коды 0–8, 11, 12, 14–31) категорически запрещены. Если ваша строка содержит хотя бы один такой символ, попытка передать её через границу «клиент-сервер» приведет к фатальной ошибке сериализации, так как 1С не сможет сформировать валидный XML-пакет.
Рассмотрим наиболее распространенные случаи, когда «плохие» символы попадают в данные:
DataMatrix или GS1-128 как разделитель групп данных. Если сканер штрихкода настроен на передачу спецсимволов «как есть» и данные записываются в строковый реквизит, попытка передать эту строку на сервер вызовет ошибку.ТекстовыйДокумент.Прочитать().Если нам не важны спецсимволы и мы хотим просто гарантировать работоспособность системы, самым простым решением будет удаление всех недопустимых символов перед передачей данных. Разберем по шагам, как написать универсальную функцию для такой очистки.
Проанализируем пример кода, который перебирает строку и оставляет только разрешенные символы:
Функция ОчиститьСтрокуДляСериализации(ВходящаяСтрока) Экспорт
Результат = "";
Для Позиция = 1 По СтрДлина(ВходящаяСтрока) Цикл
КодСимвола = КодСимвола(ВходящаяСтрока, Позиция);
// Разрешаем символы больше 31, а также Таб, ПС и ВК
Если КодСимвола > 31
Или КодСимвола = 9
Или КодСимвола = 10
Или КодСимвола = 13 Тогда
Результат = Результат + Сред(ВходящаяСтрока, Позиция, 1);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Важный момент: Для длинных строк метод конкатенации в цикле (Результат + Символ) может работать медленно. В таких случаях лучше использовать СтрЗаменить() для конкретных известных символов-вредителей, таких как Символы.ПФ (прогон страницы, код 12) или символ с кодом 29.
Если нам необходимо передать строку, сохранив в ней абсолютно все символы (например, для последующей печати штрихкода на сервере), очистка нам не подойдет. В этом случае мы воспользуемся кодированием в Base64. Этот формат превращает любые бинарные данные в строку, состоящую только из латинских букв и цифр, которые абсолютно безопасны для XML.
Рассмотрим, как это реализовать с помощью встроенных средств платформы:
// На стороне отправителя (например, на клиенте)
ДвоичныеДанныеСтроки = ПолучитьДвоичныеДанныеИзСтроки(МояПроблемнаяСтрока);
БезопаснаяСтрока = Base64Строка(ДвоичныеДанныеСтроки);
// Теперь БезопаснаяСтрока можно передавать через &НаСервере без ошибок
// На стороне получателя (например, на сервере)
ДвоичныеДанныеРезультат = Base64Значение(БезопаснаяСтрока);
ОригинальнаяСтрока = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанныеРезультат);
Использование Base64 увеличивает объем передаваемых данных примерно на 33%, но гарантирует 100% сохранность информации и отсутствие ошибок сериализации.
Платформа 1С умеет передавать объект типа ДвоичныеДанные между клиентом и сервером особым образом. Если вы поместите строку в ДвоичныеДанные, она будет передана как бинарный поток, минуя текстовые узлы XML, где действуют ограничения на коды символов. Это более эффективно, чем Base64, для больших объемов информации.
Выясним, как применить этот метод при вызове серверной функции:
&НаКлиенте
Процедура ОбработатьФайлНаСервере()
// Читаем файл в двоичные данные вместо строки
ДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
// Передаем объект "ДвоичныеДанные" в серверный метод
Результат = ВыполнитьОбработкуНаСервере(ДанныеФайла);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ВыполнитьОбработкуНаСервере(ДанныеФайла)
// Преобразуем в строку только там, где это нужно,
// и обрабатываем ее с осторожностью
Текст = ПолучитьСтрокуИзДвоичныхДанных(ДанныеФайла);
// ... логика обработки ...
Возврат "Ок";
КонецФункции
Ошибка недопустимого символа XML — это не баг вашей конфигурации, а фундаментальное ограничение транспортного протокола 1С. Чтобы ваша программа работала стабильно, придерживайтесь следующих правил:
ДвоичныеДанные вместо типа Строка.Base64.GS (код 29) — самый частый виновник падения интерфейса.Мы проанализировали природу сериализации в 1С и теперь знаем, что строки в управляемом приложении — это не просто набор байтов, а часть XML-документа, требующая соблюдения определенных правил безопасности. Применяя описанные методы, вы сделаете свои решения более надежными и устойчивыми к некорректным входным данным.