Интеграция с логистическими провайдерами — одна из самых частых задач при автоматизации торговых систем в 1С. Служба доставки СДЭК предоставляет разработчикам программный интерфейс (API) для создания заказов, расчета стоимости доставки и отслеживания статусов отправлений. Однако при работе со старыми протоколами СДЭК (в частности, XML API версии 1.5) программисты часто сталкиваются с неочевидными техническими трудностями.
В этой статье мы подробно разберем, как правильно сформировать XML-запрос в 1С, корректно настроить заголовки HTTP-запроса, закодировать тело сообщения и отправить его методом POST на сервера СДЭК. Также мы рассмотрим критическую ошибку авторизации, связанную с формированием цифровой подписи, и дадим рекомендации по переходу на современную версию API v2.0.
При попытке напрямую отправить XML-документ через POST-запрос на адрес СДЭК разработчики часто получают пустые ответы или ошибки авторизации. Проанализируем причину такого поведения. Серверный скрипт СДЭК (например, status_report_h.php) не умеет парсить "сырой" XML из тела запроса (Raw XML). Вместо этого он ожидает данные в формате application/x-www-form-urlencoded (аналог отправки данных из обычной HTML-формы). При этом вся XML-структура должна передаваться в качестве значения единственного параметра с именем xml_request.
Если мы просто передадим XML без предварительного URL-кодирования, спецсимволы (такие как угловые скобки, амперсанды и кавычки) нарушат синтаксис HTTP-запроса, и сервер не сможет его обработать. Выясним, как поэтапно решить эту задачу в 1С.
---
Для создания XML-документа воспользуемся специализированным объектом ЗаписьXML. Это гораздо надежнее, чем склеивание строк вручную, так как объект автоматически контролирует закрытие тегов и кодировку. Ниже представлен пример формирования XML-запроса отслеживания статуса заказа.
// Создаем объект для записи XML в строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();
// Корневой элемент отчета
ЗаписьXML.ЗаписатьНачалоЭлемента("StatusReport");
// Записываем системные атрибуты авторизации
ЗаписьXML.ЗаписатьАтрибут("account", Логин);
ЗаписьXML.ЗаписатьАтрибут("date", СтрокаДаты);
ЗаписьXML.ЗаписатьАтрибут("secure", ЦифроваяПодпись);
// Сведения о заказе, статус которого мы хотим получить
ЗаписьXML.ЗаписатьНачалоЭлемента("order");
ЗаписьXML.ЗаписатьАтрибут("DispatchNumber", НомерОтправления); // Номер накладной СДЭК
ЗаписьXML.ЗаписатьКонецЭлемента(); // order
ЗаписьXML.ЗаписатьКонецЭлемента(); // StatusReport
СтрXML = ЗаписьXML.Закрыть();
---
Это самый важный нюанс авторизации в API СДЭК v1.5, из-за которого большинство разработчиков получают ошибку авторизации. Передавать пароль в чистом виде в атрибут secure нельзя! СДЭК требует формирования криптографической подписи по алгоритму MD5.
Подпись рассчитывается по следующему правилу: берется дата запроса (в формате ISO 8601), затем ставится разделитель амперсанд &, после чего добавляется секретный пароль API. От получившейся строки вычисляется MD5-хеш в нижнем регистре.
Рассмотрим, как реализовать этот расчет встроенными средствами платформы 1С:
// 1. Формируем дату строго в формате ISO 8601 (ГГГГ-ММ-ДДThh:mm:ss)
СтрокаДаты = Формат(ТекущаяДата(), "ДФ=""гггг-ММ-дд'T'ЧЧ:мм:сс""");
// 2. Склеиваем строку для хеширования
СтрокаДляХеша = СтрокаДаты + "&" + ПарольОтAPI;
// 3. Вычисляем MD5 с помощью объекта "ХешированиеДанных"
ХешДанных = Новый ХешированиеДанных(ХешФункция.MD5);
ХешДанных.Добавить(СтрокаДляХеша);
// Преобразуем двоичные данные хеша в строку в нижнем регистре без пробелов
ЦифроваяПодпись = НРег(СтрЗаменить(Строка(ХешДанных.ХешСумма), " ", ""));
Важное примечание: Передаваемая в атрибуте date строка должна символ-в-символ совпадать с той строкой, которая использовалась для генерации подписи secure. В противном случае сервер отклонит запрос.
---
Теперь, когда у нас есть готовая XML-строка, ее нужно подготовить для передачи в формате URL-encoded. Для этого мы должны использовать метод КодироватьСтроку, указав тип кодирования СпособКодированияСтроки.КодироватьИменаПровайдеров (это заменит все служебные символы на их шестнадцатеричные эквиваленты с префиксом %).
Затем мы конструируем финальное тело запроса, соединив ключ xml_request= с нашей закодированной строкой:
// Кодируем XML-строку, чтобы безопасно передать ее в POST-параметре
ЗакодированныйXML = КодироватьСтроку(СтрXML, СпособКодированияСтроки.КодироватьИменаПровайдеров);
// Собираем тело запроса
ТелоPOSTЗапроса = "xml_request=" + ЗакодированныйXML;
---
Настроим отправку данных. Поскольку СДЭК работает по защищенному протоколу HTTPS, нам обязательно нужно использовать объект ЗащищенноеСоединениеOpenSSL. В противном случае платформа 1С выбросит исключение при попытке установить соединение.
Для удобства работы и гибкой настройки интеграции полезно иметь универсальную функцию парсинга URI, которая разбирает полный адрес ресурса на составляющие (хост, порт, путь на сервере). Ниже представлен готовый рабочий код отправки запроса:
// Входные параметры интеграции
АдресРесурса = "https://integration.cdek.ru/status_report_h.php";
СтруктураURI = ПолучитьСтруктуруURI(АдресРесурса);
// Создаем защищенное соединение SSL
Защита = Новый ЗащищенноеСоединениеOpenSSL();
// Инициализируем соединение с сервером
HTTPСоединение = Новый HTTPСоединение(
СтруктураURI.Хост,
СтруктураURI.Порт,
,,, // Логин и пароль для HTTP-авторизации здесь не требуются, они внутри XML
60, // Таймаут соединения в секундах
Защита
);
// Задаем заголовок Content-Type, имитирующий отправку веб-формы
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
// Создаем HTTP-запрос
HTTPЗапрос = Новый HTTPЗапрос(СтруктураURI.ПутьНаСервере, Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоPOSTЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Попытка
// Отправляем POST-запрос на обработку
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Если HTTPОтвет.КодСостояния = 200 Тогда
ТекстОтвета = HTTPОтвет.ПолучитьТелоКакСтроку("UTF-8");
// Переходим к парсингу полученного XML-ответа
ОбработатьОтветСДЭК(ТекстОтвета);
Иначе
Сообщить("Ошибка обмена со СДЭК. Код состояния сервера: " + HTTPОтвет.КодСостояния);
КонецЕсли;
Исключение
Сообщить("Не удалось установить связь с сервером СДЭК: " + ОписаниеОшибки());
КонецПопытки;
Приведем вспомогательную функцию разбора URI, которая избавляет разработчика от необходимости вручную прописывать хосты и пути при смене тестового контура на рабочий:
Функция ПолучитьСтруктуруURI(Знач СтрокаURI)
СтрокаURI = СокрЛП(СтрокаURI);
// Вычленяем схему (http/https)
Схема = "";
Позиция = Найти(СтрокаURI, "://");
Если Позиция > 0 Тогда
Схема = НРег(Лев(СтрокаURI, Позиция - 1));
СтрокаURI = Сред(СтрокаURI, Позиция + 3);
КонецЕсли;
// Вычленяем хост и путь на сервере
Хост = СтрокаURI;
ПутьНаСервере = "";
Позиция = Найти(Хост, "/");
Если Позиция > 0 Тогда
ПутьНаСервере = Сред(Хост, Позиция);
Хост = Лев(Хост, Позиция - 1);
КонецЕсли;
// Определяем порт по умолчанию
Порт = Неопределено;
Если Схема = "https" Тогда
Порт = 443;
ИначеЕсли Схема = "http" Тогда
Порт = 80;
КонецЕсли;
// Проверяем, указан ли кастомный порт в хосте
ПозицияПорта = Найти(Хост, ":");
Если ПозицияПорта > 0 Тогда
Порт = Число(Сред(Хост, ПозицияПорта + 1));
Хост = Лев(Хост, ПозицияПорта - 1);
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("Хост", Хост);
Результат.Вставить("Порт", Порт);
Результат.Вставить("ПутьНаСервере", ПутьНаСервере);
Возврат Результат;
КонецФункции
---
Сервер СДЭК возвращает ответ в виде XML-структуры, содержащей детальную информацию об истории движения посылки. Разберем пример быстрого последовательного парсинга ответа с помощью объекта ЧтениеXML:
Процедура ОбработатьОтветСДЭК(ТекстОтвета)
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(ТекстОтвета);
Пока Чтение.Прочитать() Цикл
// Ищем элементы с информацией по заказу
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "Order" Тогда
// Считываем атрибуты элемента Order
Пока Чтение.ПрочитатьАтрибут() Цикл
Если Чтение.Имя = "DispatchNumber" Тогда
НомерНакладной = Чтение.Значение;
ИначеЕсли Чтение.Имя = "StatusName" Тогда
ТекущийСтатус = Чтение.Значение;
Сообщить("Заказ № " + НомерНакладной + " имеет статус: " + ТекущийСтатус);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
---
Если вам требуется оперативно получать информацию по небольшому числу заказов и вы не хотите усложнять систему формированием XML-структур на стороне 1С, протокол API v1.5 СДЭК позволяет обойтись стандартным GET-запросом.
Скрипт приема данных поддерживает передачу всех ключевых параметров (аккаунт, подпись, номера накладных) прямо в строке URL. Посмотрим на структуру такого запроса:
https://integration.cdek.ru/status_report_h.php?account=ЛОГИН&secure=ХЕШ_MD5&change_period_id=ИД&showhistory=1
В этом случае вам достаточно собрать строку GET-параметров, подставив туда рассчитанный MD5-хеш подписи, и отправить простой HTTP-запрос GET. В ответ придет точно такой же XML-документ со статусами заказов.
---
Рассмотренный в статье протокол интеграции на базе PHP-скриптов и XML-пакетов (версия API 1.5) на сегодняшний день признан компанией СДЭК устаревшим. СДЭК активно выводит из эксплуатации старые серверные роуты, из-за чего интеграция по старым схемам может работать медленно или периодически возвращать ошибку 404 Not Found.
Настоятельно рекомендуется планировать перевод ваших информационных систем на API СДЭК v2.0. Проанализируем ключевые отличия новой версии:
Authorization: Bearer [токен].Применение правильных методов кодирования данных и понимание сетевых протоколов позволяет реализовать надежное и стабильное взаимодействие между 1С и внешними информационными системами служб доставки.