При разработке мобильных приложений на платформе 1С:Предприятие 8 разработчики часто сталкиваются с необходимостью интеграции со сторонними веб-службами (например, SMS-шлюзами, логистическими службами или государственными информационными системами). Традиционным и привычным способом интеграции в экосистеме 1С является использование веб-сервисов SOAP через встроенный механизм WSОпределения. Однако при попытке перенести работающий на настольном компьютере код в мобильное приложение на устройствах под управлением Android или iOS может возникнуть критическая ошибка разбора XML, полностью блокирующая работу механизма.
В данной статье мы подробно проанализируем причины этой проблемы, выясним, почему один и тот же код ведет себя по-разному на персональном компьютере и мобильном устройстве, а также разберем три практических способа решения этой задачи.
Типичный сценарий: на стационарном компьютере или сервере 1С под управлением ОС Windows код инициализации веб-сервиса отрабатывает без нареканий, но при запуске на планшете или смартфоне та же самая строка кода вызывает аварийное завершение процесса:
Определение = Новый WSОпределения("https://sms4b.ru/webservices/sms.asmx?WSDL");
Платформа генерирует ошибку следующего вида:
Ошибка при вызове конструктора (WSОпределения): Ошибка разбора XML: [2,190] Ошибка: xmlns:tns: 'SMS client' is not a valid URI
Давайте проанализируем ситуацию и выясним истинную техническую причину такого поведения:
XmlPullParser в Android), строго следующие спецификациям консорциума W3C.xmlns:tns="SMS client"). Согласно строгим стандартам W3C и RFC 3986, значение атрибута xmlns должно представлять собой валидный URI (Uniform Resource Identifier), в котором использование пробелов абсолютно недопустимо. Строгий мобильный парсер видит пробел в строке 'SMS client', считает спецификацию WSDL некорректной и немедленно прекращает импорт схемы, в то время как Windows-версия просто игнорирует эту неточность.Рассмотрим самый надежный способ обхода этой ошибки, не требующий изменения серверной части стороннего провайдера или ожидания исправлений от его техподдержки. Проанализируем суть технологии SOAP: любой SOAP-запрос — это обычный POST-запрос по протоколу HTTP(S), в теле которого передается XML-пакет определенной структуры (так называемый SOAP-конверт или Envelope).
Мы можем полностью отказаться от капризного конструктора WSОпределения и сформировать запрос вручную. Разберем этот процесс по шагам:
ЗащищенноеСоединениеOpenSSL.HTTPСоединение и подготовим HTTPЗапрос.Content-Type и SOAPAction).ЧтениеXML.Посмотрим на пример практической реализации этого метода:
Функция ОтправитьSMSЧерезHTTPSOAP(НомерТелефона, ТекстСообщения) Экспорт
// Шаг 1. Формируем тело SOAP-конверта в виде XML-строки
ТелоЗапроса =
"<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" " + Символы.ПС +
"xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" " + Символы.ПС +
"xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">" + Символы.ПС +
" <soap:Body>" + Символы.ПС +
" <SendSMS xmlns=""http://sms4b.ru/ws/"">" + Символы.ПС +
" <Login>МойЛогин</Login>" + Символы.ПС +
" <Password>МойПароль</Password>" + Символы.ПС +
" <SourceAddress>MyBrand</SourceAddress>" + Символы.ПС +
" <DestinationAddress>" + НомерТелефона + "</DestinationAddress>" + Символы.ПС +
" <Text>" + ТекстСообщения + "</Text>" + Символы.ПС +
" </SendSMS>" + Символы.ПС +
" </soap:Body>" +
"</soap:Envelope>";
// Шаг 2. Инициализируем защищенное соединение для работы по HTTPS
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
// Шаг 3. Настраиваем подключение к серверу
АдресСервера = "sms4b.ru";
Таймаут = 15;
Соединение = Новый HTTPСоединение(АдресСервера, , , , , Таймаут, ЗащищенноеСоединение);
// Шаг 4. Готовим HTTP-запрос
Ресурс = "/ws/sms.asmx";
Запрос = Новый HTTPЗапрос(Ресурс);
// Задаем обязательные HTTP-заголовки для SOAP веб-службы
Запрос.Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
Запрос.Заголовки.Вставить("SOAPAction", """http://sms4b.ru/ws/SendSMS""");
Запрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
// Шаг 5. Отправляем запрос и анализируем полученный ответ
Попытка
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 200 Тогда
// Успешный запрос, разбираем возвращаемый XML
Возврат РазобратьОтветSOAP(Ответ.ПолучитьТелоКакСтроку());
Иначе
ЗаписатьВЖурналРегистрации("Отправка SMS", СистемнаяИнформация.УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось отправить запрос. Код ошибки сервера: " + Ответ.КодСостояния);
Возврат Ложь;
КонецЕсли;
Исключение
ЗаписатьВЖурналРегистрации("Отправка SMS", СистемнаяИнформация.УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка сетевого соединения: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Ложь;
КонецПопытки;
КонецФункции
Этот подход гарантирует абсолютно стабильную работу на любых мобильных устройствах, поскольку он полностью обходит стадию автоматического разбора тяжелого и капризного файла WSDL встроенными средствами платформы 1С и взаимодействует напрямую с эндпоинтом.
Если использование стандартных механизмов 1С для работы с веб-сервисами (таких как WSПрокси) для вас принципиально, и вы не хотите формировать XML вручную, рассмотрим варианты исправления самой схемы:
А. Поиск альтернативного адреса подключения (Endpoint)
Зачастую крупные провайдеры предоставляют несколько версий шлюзов или параллельно поддерживают разные структуры адресов. Например, как показывает практика работы с SMS4B, адрес https://sms4b.ru/webservices/sms.asmx?WSDL содержит в схеме пробелы и вызывает падение парсера 1С на мобильной платформе. В то же время альтернативный адрес https://sms4b.ru/ws/sms.asmx?WSDL базируется на более строгой и чистой XML-схеме, в которой нет недопустимых URI. Попробуйте переключить ваше мобильное приложение на альтернативный адрес.
Б. Локальное размещение исправленной схемы
Если провайдер предоставляет только один WSDL-файл и в нем содержатся ошибки, мы можем исправить схему самостоятельно:
xmlns:tns="SMS client" на валидное xmlns:tns="SMS_client" или укажите реальный URL-адрес без пробелов).WSОпределения, указав путь к локальной копии исправленного WSDL-файла на устройстве или URL вашего собственного сервера.
// Пример инициализации из локального макета конфигурации
ПутьКФайлу = ПолучитьИмяВременногоФайла("wsdl");
ДвоичныеДанныеСхемы = ПолучитьМакет("ИсправленнаяСхемаWSDL");
ДвоичныеДанныеСхемы.Записать(ПутьКФайлу);
Определение = Новый WSОпределения(ПутьКФайлу);
// Далее создаем WSПрокси стандартным образом
Использование SOAP-протокола в мобильной разработке постепенно уходит в прошлое. SOAP-конверты создают избыточный сетевой трафик за счет излишне тяжелой структуры XML-тегов, что критично в условиях нестабильного мобильного интернета и быстрее расходует заряд аккумулятора устройства. Современным и производительным стандартом является использование легкого протокола REST API с форматом обмена данными JSON.
Почти все современные SMS-сервисы предоставляют полноценные REST-интерфейсы. Интеграция через REST API в мобильной 1С реализуется чрезвычайно просто и быстро с использованием встроенных объектов HTTPСоединение, ПрочитатьJSON и ЗаписатьJSON. Авторизация при этом происходит не по логину и паролю в каждом запросе, а через безопасные API-токены (Bearer tokens).
Рассмотрим пример отправки SMS через современный REST API с передачей параметров в формате JSON:
Функция ОтправитьSMSЧерезREST(Получатель, ТекстСообщения) Экспорт
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
Соединение = Новый HTTPСоединение("api.sms-service-provider.ru", , , , , 10, ЗащищенноеСоединение);
// Подготовка структуры запроса согласно спецификации API
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("sender", "MyBrand");
ПараметрыЗапроса.Вставить("phone", Получатель);
ПараметрыЗапроса.Вставить("text", ТекстСообщения);
// Сериализация структуры в строку JSON
ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, " ", Истина);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
СтрокаJSON = ЗаписьJSON.Закрыть();
// Создание HTTP-запроса
Запрос = Новый HTTPЗапрос("/v1/sms/send");
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
// Используем современную токенизированную авторизацию
Запрос.Заголовки.Вставить("Authorization", "Bearer d83b7f29ac02e8813a48e77c08271e");
Запрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Попытка
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 200 Тогда
// SMS успешно отправлено
Возврат Истина;
Иначе
ЗаписатьВЖурналРегистрации("Отправка SMS REST", СистемнаяИнформация.УровеньЖурналаРегистрации.Предупреждение, , ,
"Ответ сервера: " + Ответ.ПолучитьТелоКакСтроку());
Возврат Ложь;
КонецЕсли;
Исключение
ЗаписатьВЖурналРегистрации("Отправка SMS REST", СистемнаяИнформация.УровеньЖурналаРегистрации.Ошибка, , ,
"Сбой соединения: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Ложь;
КонецПопытки;
КонецФункции
Подводя итоги, сформулируем основные правила работы с внешними API в мобильной платформе 1С:
WSОпределения на лету, если вы не контролируете сервер-источник. Любое малейшее нарушение стандартов разметки на стороне провайдера мгновенно сломает ваше мобильное приложение на мобильных устройствах пользователей.