В этой статье разберем, как реализовать загрузку файлов на Яндекс.Диск непосредственно из 1С 7.7. Такая задача часто возникает, когда 1С работает на удаленном сервере, и нет возможности использовать стандартный клиент Яндекс.Диска для синхронизации папок. Мы будем использовать REST API Яндекса и COM-объекты для отправки HTTP-запросов.
Основная сложность, с которой сталкиваются разработчики, — это передача самого файла. Если получение URL для загрузки (первый шаг по документации Яндекса) обычно не вызывает проблем, то как прикрепить бинарные данные файла к PUT-запросу — не всегда очевидно. Рассмотрим эту задачу по шагам.
Процесс загрузки файла на Яндекс.Диск через API состоит из двух этапов:
Автор исходного вопроса успешно справился с первым шагом, но остановился на втором. Его код получал URL, но не отправлял сам файл, потому что метод Send() вызывался без параметров.
Вот как выглядел проблемный участок кода:
... // Код получения ТехУрл (URL для загрузки)
httpobj.Open("PUT",ТехУрл,0);
httpobj.Send(); // <-- Проблема здесь: файл не передается
Сообщить("4: "+httpobj.status+":"+httpobj.statusText);
...
Чтобы решить эту проблему, нужно прочитать файл в специальный объект, который может хранить бинарные данные, и передать этот объект в качестве параметра методу Send().
Самый правильный и распространенный способ для работы с бинарными данными (такими как файлы) в среде Windows Scripting Host, доступной из 1С 7.7, — это использование COM-объекта ADODB.Stream. Этот объект позволяет читать содержимое файла в поток (stream) данных и затем передавать этот поток в теле HTTP-запроса.
Разберем по шагам, как это работает:
ADODB.Stream. Он является частью библиотеки Microsoft ActiveX Data Objects.adTypeBinary, что соответствует значению 1.Open() подготавливает объект к работе.LoadFromFile(ПутьКФайлу) читает все содержимое файла в объект.Send(dataStream) нашего HTTP-клиента.Теперь давайте встроим этот механизм в исходный код. Ниже представлен полный работающий пример процедуры, которая загружает файл на Яндекс.Диск.
Процедура глЗагрузитьОбновитьФайлНаЯндексДиске(token, УрлКYandexDisk, overwrite, ПутьКФайлуДляЗагрузки) Экспорт
// Этап 1: Получение URL для загрузки
httpobj=CreateObject("winhttp.winhttprequest.5.1");
httpobj.Open("GET",УрлКYandexDisk,0);
httpobj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
httpobj.setRequestHeader("Authorization","OAuth " + token);
httpobj.Send("");
Сообщить("1: "+УрлКYandexDisk); // папка на Я.Диске, куда требуется закачка
Сообщить("2: "+httpobj.status+":"+httpobj.statusText);
// Простая обработка JSON-ответа для получения ссылки
Текст=0;
Текст=СоздатьОбъект("Текст");
Текст=httpobj.ResponseText;
Текст=СтрЗаменить(Текст,"{""href"":""h","h");
ТехУрл=СтрЗаменить(Текст,"""}","");
Сообщить("3: "+ТехУрл); //технический url для закачки на Я.Диск
// Этап 2: Подготовка и отправка файла
// Создаем и настраиваем объект ADODB.Stream
dataStream = СоздатьОбъект("ADODB.Stream");
dataStream.Type = 1; // Тип данных - бинарный
dataStream.Open();
dataStream.LoadFromFile(ПутьКФайлуДляЗагрузки);
// Открываем PUT-запрос по полученному URL
httpobj.Open("PUT",ТехУрл,0);
// Устанавливаем заголовок, указывающий, что мы передаем бинарный поток
httpobj.SetRequestHeader("Content-Type", "application/octet-stream");
// Отправляем содержимое файла, передавая объект потока в метод Send
httpobj.Send(dataStream);
Сообщить("4: "+httpobj.status+":"+httpobj.statusText); // Успех - это 201 Created
Сообщить("5: "+httpobj.ResponseText); // Ответ о результате закачки
dataStream.Close(); // Закрываем поток
httpobj=0;
КонецПроцедуры
Важные моменты в этом коде:
dataStream.Type = 1; — критически важная строка, которая указывает, что мы работаем с бинарными данными, а не с текстом.httpobj.SetRequestHeader("Content-Type", "application/octet-stream"); — перед отправкой файла мы меняем заголовок Content-Type. Теперь он сообщает серверу, что мы передаем "поток байтов", т.е. файл.httpobj.Send(dataStream); — ключевое изменение. Вместо пустого вызова мы передаем подготовленный поток с данными файла.В обсуждении был предложен еще один рабочий вариант, использующий MSScriptControl.ScriptControl. Этот подход может быть полезен, если по какой-то причине прямая передача COM-объекта в метод Send() не срабатывает в вашей среде.
Идея в том, чтобы выполнить строку VBScript-кода, который и вызовет нужный метод. 1С передает свои объекты в окружение скрипта, а он уже выполняет операцию.
Функция глЗагрузитьНаВебДав(ФайлИсточник, ИмяКаталога, ИмяФайла) Экспорт
x = СоздатьОбъект("Microsoft.XMLHTTP");
// Этот пример для WebDAV, но суть та же
x.Open("PUT","http://User:password@addresWebDav/" + ИмяКаталога + ИмяФайла,0);
x.setRequestHeader("Accept", "*/*");
x.setRequestHeader("Content-Type","application/binary");
// Создаем объект для выполнения скриптов
Скрипт = СоздатьОбъект("MSScriptControl.ScriptControl");
Скрипт.language = "vbscript";
// Готовим поток с файлом
Stream = СоздатьОбъект("ADODB.Stream");
Stream.Mode = 3;
Stream.Type = 1;
Stream.Open();
Stream.LoadFromFile(ФайлИсточник);
// Передаем наши COM-объекты в среду выполнения скрипта
Скрипт.AddObject("s", Stream);
Скрипт.AddObject("x", x);
// Выполняем код на VBScript, который читает поток и вызывает Send
Скрипт.Eval("x.Send(s.Read())");
Stream.Close();
Возврат x.Status;
КонецФункции // ЗагрузитьНаВебДав
Этот метод немного сложнее, но является надежным запасным вариантом. Здесь используется метод Stream.Read(), который читает все содержимое потока и возвращает его, а результат уже передается в x.Send().
В коде используется переменная token. Это OAuth-токен, который необходим для авторизации ваших запросов к API Яндекса. Его нужно получить один раз вручную:
yandex_disk_write).https://oauth.yandex.ru/authorize?response_type=token&client_id=<ВАШ_ClientID>Этот токен вы и будете передавать в процедуру в качестве параметра token.
Приведенный код для краткости не содержит проверок. В реальных задачах обязательно проверяйте код ответа сервера после каждого запроса.
200 OK.201 Created.httpobj.status и httpobj.statusText.Яндекс.Диск также поддерживает протокол WebDAV, который позволяет работать с диском как с сетевой папкой через HTTP-запросы. Этот подход может быть проще, так как не требует первого шага с получением временной ссылки.
https://webdav.yandex.ruhttps://webdav.yandex.ru/my_folder/sale.jpg.Пример кода из сообщения №4 как раз демонстрирует работу по этому протоколу. Это отличная альтернатива для упрощения кода.