Вводные
1. Конфигурация на 1С 8.3 с каталогом товаров
2. Нужно выгрузить данные в аккаунт AliExpress с картинками и описанием
3. Документация https://developers.aliexpress.com/en/doc.htm?docId=108970&docType=1
Реализация
Создание приложения на стороне AliExpress
Для регистрации как разработчик нужно иметь аккаунт продавца. Для регистрации нужно перейти на https://console.aliexpress.com Сам регистрировался как Self developer, различия можно почитать в документации. регистрация проходит 2-3 дня после чего на почту (может отличаться от почты аккаунта продавца) приходит уведомление.
В админ консоли после добавления приложения нужно в его настройках указать сайт ответа для получения ключа. Нужно для последующего получения ключа.
Получение ключа доступа
Ключ получается на магазин, поэтому сначала нужно авторизоваться в браузере под нужным магазином.
После перейти по ссылке получения ключа
https://oauth.aliexpress.com/authorize?response_type=code&client_id={AppKey}&redirect_uri={CallbackUrl}
&state=1212&view=web&sp=ae
Отобразится страница разрешения доступа, при подтверждении которой будет сделан перевод на страницу формата
{CallbackUrl}?code={code}&state=1212
Поле нужно получить токен доступа API, для Self Developer он выдается на год.
Описание формата получения на странице https://developers.aliexpress.com/en/doc.htm?docId=108969&docType=1
Пример
При успешном запросе получаем JSON с "access_token", который в дальнейшем будем использовать в запросах
Запросы к сервису
Все запросы делаю через POST, формат по смыслу похож на SOAP. Формат "application/x-www-form-urlencoded".
Получение списка категорий.
Функция ПолучитьСписокКатегорий(ИдентификаторКатегории, НастройкаОбмена) Экспорт
МассивДанные = Новый Массив;
ТЗ = аэ_СерверТранспорт.ПолучитьТаблицуПараметров(НастройкаОбмена);
аэ_СерверТранспорт.ДобавитьВТаблицаПараметровЗапроса(ТЗ, "method", "aliexpress.solution.seller.category.tree.query");
аэ_СерверТранспорт.ДобавитьВТаблицаПараметровЗапроса(ТЗ, "category_id", Формат(ИдентификаторКатегории, "ЧН=; ЧГ=0"));
аэ_СерверТранспорт.ДобавитьВТаблицаПараметровЗапроса(ТЗ, "filter_no_permission", "true");
СоответствиеОтвет = аэ_СерверТранспорт.ЗапросКСервису(ТЗ,,НастройкаОбмена);
Если СоответствиеОтвет <> неопределено Тогда
МассивДанные = СоответствиеОтвет
.Получить("aliexpress_solution_seller_category_tree_query_response")
.Получить("children_category_list")
.Получить("category_info");
КонецЕсли;
Возврат МассивДанные;
КонецФункции
В параметрах используется набор стандартных параметров, в том числе текущая дата, при обработке проверяется разность времени.
Таблица стандартных параметров
Функция ПолучитьТаблицуПараметров(НастройкаОбмена) Экспорт
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Ключ");
ТЗ.Колонки.Добавить("Значение");
ДобавитьВТаблицаПараметровЗапроса(ТЗ, "app_key", НастройкаОбмена.КлючПриложения);
ДобавитьВТаблицаПараметровЗапроса(ТЗ, "format", "json");
ДобавитьВТаблицаПараметровЗапроса(ТЗ, "partner_id", "apidoc");
ДобавитьВТаблицаПараметровЗапроса(ТЗ, "session", НастройкаОбмена.КлючСессии);
ДобавитьВТаблицаПараметровЗапроса(ТЗ, "sign_method", "md5");
ДобавитьВТаблицаПараметровЗапроса(ТЗ, "timestamp", Формат(ТекущаяДата() + 3*60*60, "ДФ='гггг-ММ-дд ЧЧ:мм:сс'"));
ДобавитьВТаблицаПараметровЗапроса(ТЗ, "v", "2.0");
Возврат ТЗ;
КонецФункции
При формировании тела запроса формируется подпись "sign", которая является хешем сериализованного отсортированного массива параметров с оберткой в SecretKey. Ключ image_bytes пропускается, так как он используется в отправки картинок и содержит двоичные данные.
Формирование подписи и тела запроса
Функция ПолучитьХешТаблицыПараметров(ТЗ, НастройкаОбмена) Экспорт
ТЗ.Сортировать("Ключ");
СтрокаДанные = "";
СтрокаДанные = СтрокаДанные + НастройкаОбмена.СекретПриложения;
Для каждого СтрТ Из ТЗ Цикл
Если СтрТ.Ключ = "image_bytes" Тогда
Продолжить;
КонецЕсли;
СтрокаДанные = СтрокаДанные + СтрТ.Ключ + СтрТ.Значение;
КонецЦикла;
СтрокаДанные = СтрокаДанные + НастройкаОбмена.СекретПриложения;
Возврат MD5ХешСтрока(СтрокаДанные);
КонецФункции
Функция ПолучитьСтрокаДанные(ТЗ, НастройкаОбмена)
СтрокаХеш = ПолучитьХешТаблицыПараметров(ТЗ, НастройкаОбмена);
СтрокаДанные = "";
Для каждого СтрТ Из ТЗ Цикл
СтрокаДанные = СтрокаДанные + СтрТ.Ключ + "=" + СтрТ.Значение + "&";
КонецЦикла;
СтрокаДанные = СтрокаДанные + "sign=" + СтрокаХеш;
Возврат СтрокаДанные;
КонецФункции
При наличии символа "&" и подобных в строках запроса (наименование товара, описание товара) проверка на sign не проходит. Решение:
Функция В_JSON_СимволыВнеASCII(СоответствиеДанные, Отказ = Ложь) Экспорт
ИспользоватьДвойныеКавычки = Истина;
ЭкранироватьСлэш = Ложь;
ПараметрыЗаписиJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет,,,ЭкранированиеСимволовJSON.СимволыВнеASCII);
Попытка
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписиJSON);
ЗаписатьJSON(ЗаписьJSON, СоответствиеДанные);
СтрокаДанные = ЗаписьJSON.Закрыть();
ЗаменитьНаЮникодСпецСимволы(СтрокаДанные);
Возврат СтрокаДанные;
Исключение
Отказ = Истина;
Сообщить(ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
//--
Процедура ЗаменитьНаЮникодСпецСимволы(Строка)
СтрокаСпецСимволов = "+-?&";
Для Счетчик = 1 По СтрДлина(СтрокаСпецСимволов) Цикл
СпецСивол = Сред(СтрокаСпецСимволов, Счетчик, 1);
Если СтрНайти(Строка, СпецСивол) > 0 Тогда
СимволЮникод = DecToAny(КодСимвола(СпецСивол), 16);
СимволЮникод = "00000" + СимволЮникод;
СимволЮникод = Прав(СимволЮникод, 4);
СимволЮникод = "\u" + СимволЮникод;
Строка = СтрЗаменить(Строка, СпецСивол, СимволЮникод);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Функция DecToAny(Знач тЗначение, тОснование)
тРезультат = "";
Пока тЗначение > 0 Цикл
тРезультат = Сред("0123456789abcdefghijklmnopqrstuvwxyz", тЗначение%тОснование + 1, 1) + тРезультат;
тЗначение = Цел(тЗначение/тОснование) ;
КонецЦикла;
Возврат тРезультат;
КонецФункции
Обработка ответа
В ответе может быть несколько вариантов ошибки.
1. Выраженные через код состояния
2. При коде состояния 200 определенного формата массив ответа.
Запрос с обработкой ошибки
Функция ЗапросКСервису(ТЗ, Отказ = Ложь, НастройкаОбмена) Экспорт
СтрокаДанные = ПолучитьСтрокаДанные(ТЗ, НастройкаОбмена);
Ответ = аэ_СерверТранспорт.POST("/router/rest", СтрокаДанные);
Если Ответ.КодСостояния = 200 Тогда
СтрокаОтвет = Ответ.ПолучитьТелоКакСтроку();
СоответствиеОтвет = аэ_ВызовСервера.ИЗ_JSON(СтрокаОтвет);
Если НЕ ЭтоОтветОшибки(СоответствиеОтвет) Тогда
Возврат СоответствиеОтвет;
Иначе
Отказ = Истина;
КонецЕсли;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Функция ЭтоОтветОшибки(СоответствиеОтвет) Экспорт
ЭтоОшибка = Истина;
СтрокаОшибка = СоответствиеОтвет.Получить("error_response");
Если ПустаяСтрока(СтрокаОшибка) Тогда
ЭтоОшибка = Ложь;
Иначе
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "" + аэ_ВызовСервера.В_JSON(СтрокаОшибка);
Сообщение.Сообщить();
КонецЕсли;
Возврат ЭтоОшибка;
КонецФункции
Отправка файлов
Используется POST с "Content-Type", "multipart/form-data;charset=utf-8;boundary="
Функция отправки картинки
Функция ВыгрузитьКартинку(Картинка, НастройкаОбмена) Экспорт
ИмяФайла = Картинка.Наименование + "." + Картинка.Расширение;
ТЗ = аэ_СерверТранспорт.ПолучитьТаблицуПараметров(НастройкаОбмена);
аэ_СерверТранспорт.ДобавитьВТаблицаПараметровЗапроса(ТЗ, "method", "aliexpress.photobank.redefining.uploadimageforsdk");
аэ_СерверТранспорт.ДобавитьВТаблицаПараметровЗапроса(ТЗ, "file_name", ИмяФайла);
аэ_СерверТранспорт.ДобавитьВТаблицаПараметровЗапроса(ТЗ, "image_bytes", Base64Строка(РаботаСФайлами.ДвоичныеДанныеФайла(Картинка)));
Возврат аэ_СерверТранспорт.ЗапросКСервисуФайл(ТЗ, ИмяФайла, НастройкаОбмена);
КонецФункции
"Склейка" тела запроса реализована по принципу предложенным Сергеем Ожерельевым //infostart.ru/public/20017/
Улучшенный вариант через потоки
Функция ПолучаемДвоичныеДанныеДляПакетныхСообщенийHTTP(Разделитель, МассивДвоичныхДанных) Экспорт
ПотокТело = Новый ПотокВПамяти();
ЗаписьДанных = Новый ЗаписьДанных(ПотокТело);
Для Каждого Стр Из МассивДвоичныхДанных Цикл
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель);
ЗаписьДанных.Записать(Стр);
КонецЦикла;
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель);
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель + "--";);
ЗаписьДанных.Закрыть();
Возврат ПотокТело.ЗакрытьИПолучитьДвоичныеДанные();
КонецФункции
Итог
Рабочее API со своими требованиями и ограничениями.
На момент публикации была ошибка создания группы товаров (не путать с категориями), ответ от техподдержки пришел через две недели, нужно заново проверять.
Проект на GitHub https://github.com/malikov-pro/taobao_sdk_1c
UPD_1: Добавил коллекцию postman для удобного тестирования работы сервиса, подход описан в //infostart.ru/1c/articles/1282851/.
UPD_2: Добавил ссылку на репозиторий с транспортом
UPD_3: Добавил вариант склейки через потоки
Благодарю за внимание.