При интеграции систем на платформе 1С с внешними веб-сервисами разработчики часто сталкиваются с необходимостью передавать сложные текстовые параметры, содержащие специальные символы. Одним из наиболее проблемных символов является обычный прямой слэш (/). Он часто встречается в номерах договоров (например, "ф1-0512/2016-1"), артикулах товаров или кодах документов.
Попытка передать такой параметр напрямую в строке URL-запроса (в качестве параметра пути или Query-параметра) неизбежно приводит к ошибкам веб-сервера вроде 404 Not Found или 400 Bad Request. В этой статье мы подробно разберем, почему возникает эта проблема, и рассмотрим несколько эффективных способов ее решения.
Символ / является зарезервированным символом в спецификации протокола HTTP. Он используется в качестве разделителя сегментов пути (Path) в URL-адресе. Когда клиент отправляет запрос, в котором значение параметра содержит слэш, веб-сервер (будь то IIS или Apache) воспринимает его как команду перехода к новому каталогу или сегменту адреса.
Даже если мы попытаемся применить стандартное URL-кодирование (Percent-Encoding), заменив слэш на %2F, это не всегда решает проблему. По соображениям безопасности многие современные веб-серверы по умолчанию блокируют запросы, содержащие закодированные слэши в путях URL, возвращая ошибку еще до того, как запрос будет передан на обработку в базу 1С.
Давайте по шагам разберем варианты обхода этого ограничения, начиная с самого правильного и заканчивая альтернативными сценариями.
Самый надежный способ передачи сложных структур данных, содержащих любые спецсимволы, кириллицу или длинный текст — это полный отказ от передачи параметров в строке адреса (URL) или заголовках. Вместо этого следует использовать HTTP-метод POST (или PUT) и передавать данные в теле запроса в формате JSON.
Рассмотрим, как правильно реализовать этот подход на встроенном языке 1С.
Шаг 1. Отправка POST-запроса на стороне клиента:
Вместо формирования длинной строки URL мы создаем объект HTTPЗапрос, упаковываем наши параметры в JSON и помещаем их в тело запроса с помощью метода УстановитьТелоИзСтроки.
// Настраиваем соединение с веб-сервером
Соединение = Новый HTTPСоединение("имя_хоста_или_ip");
// Указываем относительный путь к нашему HTTP-сервису
Запрос = Новый HTTPЗапрос("/hs/MyCustomService/v1/GetContractData");
// Обязательно указываем заголовок Content-Type, чтобы сервер понял формат данных
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
// Формируем структуру с параметрами, содержащими слэш
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("ContractNumber", "ф1-0512/2016-1");
ПараметрыЗапроса.Вставить("Password", "123");
// Сериализуем структуру в JSON-строку
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
СтрокаТела = ЗаписьJSON.Закрыть();
// Помещаем JSON в тело запроса
Запрос.УстановитьТелоИзСтроки(СтрокаТела, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
// Отправляем запрос методом POST
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Шаг 2. Получение и обработка данных на стороне HTTP-сервиса 1С:
В модуле HTTP-сервиса 1С в соответствующем методе POST мы извлекаем переданную строку и десериализуем ее обратно в структуру программных объектов.
Функция ПолучитьДанныеДоговора(Запрос)
// Получаем тело запроса в виде строки UTF-8
СтрокаJSON = Запрос.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
Если ПустаяСтрока(СтрокаJSON) Тогда
Ответ = Новый HTTPСервисОтвет(400);
Ответ.УстановитьТелоИзСтроки("Пустое тело запроса");
Возврат Ответ;
КонецЕсли;
// Парсим JSON
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
Попытка
Данные = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Исключение
ЧтениеJSON.Закрыть();
Ответ = Новый HTTPСервисОтвет(400);
Ответ.УстановитьТелоИзСтроки("Ошибка разбора JSON: " + ОписаниеОшибки());
Возврат Ответ;
КонецПопытки;
// Теперь мы можем безопасно обратиться к нашему номеру со слэшем
НомерДоговора = Данные.ContractNumber; // Получим исходное значение: "ф1-0512/2016-1"
Пароль = Данные.Password;
// Выполняем бизнес-логику...
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки("Данные успешно обработаны");
Возврат Ответ;
КонецФункции
Если бизнес-логика или спецификации внешнего API требуют использования исключительно метода GET, передавать слэш в параметрах пути (Path Parameters) вида /hs/service/GetContract/ф1-0512/2016-1 категорически не рекомендуется. Платформа 1С не сможет сопоставить URL с шаблоном вашего HTTP-сервиса, поскольку решит, что в адресе содержится дополнительный сегмент пути.
Вместо этого параметры необходимо передавать в секции запроса (Query Parameters) после вопросительного знака: /hs/service/GetContract?ContractNumber=значение. При этом значение параметра обязательно должно быть закодировано.
Для преобразования спецсимволов во встроенном языке 1С используется функция КодироватьСтроку с указанием способа кодирования СпособКодированияСтроки.КодировкаURL.
Проанализируем пример кодирования:
ИсходныйНомер = "ф1-0512/2016-1";
КодированныйНомер = КодироватьСтроку(ИсходныйНомер, СпособКодированияСтроки.КодировкаURL);
// Значение переменной КодированныйНомер станет: "%D1%841-0512%2F2016-1"
// Формируем безопасный GET-запрос
АдресЗапроса = "/hs/MyCustomService/v1/GetContract?ContractNumber=" + КодированныйНомер;
Запрос = Новый HTTPЗапрос(АдресЗапроса);
При получении такого запроса в HTTP-сервисе 1С платформа автоматически декодирует параметры, и в коллекции Запрос.ПараметрыЗапроса вы получите исходную строку со слэшем без дополнительных манипуляций:
НомерДоговора = Запрос.ПараметрыЗапроса.Получить("ContractNumber"); // Вернет "ф1-0512/2016-1"
Если вы все же используете передачу параметров со слэшем внутри URL и получаете ошибку от веб-сервера (даже при URL-кодировании), вам потребуется перенастроить веб-сервер, на котором опубликована информационная база 1С.
Для Microsoft IIS:
По умолчанию IIS блокирует символы двойного экранирования. Чтобы разрешить обработку закодированных символов, откройте файл web.config в корневом каталоге публикации вашей базы 1С и добавьте в секцию <system.webServer> следующую настройку фильтрации запросов:
<configuration>
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
</system.webServer>
</configuration>
Для Apache:
По умолчанию веб-сервер Apache возвращает ошибку 404 при попытке использовать закодированный слэш %2F в пути запроса. Чтобы исправить это поведение, откройте конфигурационный файл Apache (httpd.conf) или файл настроек конкретного виртуального хоста и добавьте директиву:
AllowEncodedSlashes On
После внесения изменений обязательно перезапустите службу веб-сервера для применения новых настроек.
В ситуациях, когда у вас нет доступа к конфигурационным файлам веб-сервера IIS или Apache (например, при использовании облачных хостингов), а передавать спецсимволы в URL крайне необходимо, отличным выходом станет использование кодирования в Base64.
Схема работы выглядит следующим образом:
/ преобразуется в алфавитно-цифровой набор символов, который безопасен для любого веб-сервера.Рассмотрим пример декодирования Base64 на стороне HTTP-сервиса 1С:
// Получаем переданный Base64-параметр из запроса
ПараметрBase64 = Запрос.ПараметрыЗапроса.Получить("ContractNumber");
Если ЗначениеЗаполнено(ПараметрBase64) Тогда
// Декодируем Base64 в двоичные данные
ДвоичныеДанныеДекод = Base64Значение(ПараметрBase64);
// Для получения текста записываем двоичные данные во временный файл
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt");
ДвоичныеДанныеДекод.Записать(ИмяВременногоФайла);
// Считываем текст в кодировке UTF-8
ЧтениеТекста = Новый ЧтениеТекста(ИмяВременногоФайла, КодировкаТекста.UTF8);
ИсходныйНомерДоговора = ЧтениеТекста.Прочитать();
ЧтениеТекста.Закрыть();
// Удаляем временный файл за собой
УдалитьФайлы(ИмяВременногоФайла);
КонецЕсли;
Мы проанализировали различные методы передачи символа слэша в HTTP-сервисах 1С. Подведем краткий итог по выбору оптимального решения:
?), предварительно закодировав их функцией КодироватьСтроку().allowDoubleEscaping="true" для IIS или AllowEncodedSlashes On для Apache.