Имя: Пароль:
1C
1С v8
Отправка файла на Яндекс Диск
0 yurii-syrkin
 
22.08.19
14:29
Здравствуйте. Появилась задача отправить большой файл на почту. Обычной отправкой сделать это не получается, файл слишком большой. Решили выгружать его на яндекс диск и в письме писать ссылку на скачивание файла с яндекс диска. Копирую следующим кодом:

        Путь1 = ИмяФайла;
    
    Файл = Новый Файл(Путь1);
    
    ИмяФайла = Файл.Имя;
    
    Путь2 =  "https://"; + Логин + ":" + Пароль + "@webdav.yandex.ru/" + ИмяФайла;
    
    КопироватьФайл(Путь1, Путь2);

Копируется нормально, потом в яндекс диске этот файл вижу. Но не пойму как получить ссылку на скачивание файла. Мне же нужно именно программно получить эту ссылку, а не заходить потом на яндекс диск и интерфейсными кнопками её копировать. Вот такая вот проблема. Спасибо.
1 dka80
 
22.08.19
14:32
2 Йохохо
 
22.08.19
14:43
3 yurii-syrkin
 
22.08.19
15:01
Чёт не могу это к 1С применить. Только не бейте сильно)
4 yurii-syrkin
 
22.08.19
17:04
Приложение зарегистрировал, токен получил. Как писать код в 1С не знаю. Ну помогите, что вам сложно что ли
5 dezss
 
22.08.19
17:07
(4) HTTPСоединение и HTTPЗапрос используй.
Описание есть в СП.
6 yurii-syrkin
 
22.08.19
17:11
Соединение = Новый HTTPСоединение("cloud-api.yandex.net", ,"Логин", "Пароль");
    
    ИмяФайла_ = СтрЗаменить(ИмяФайла, "\", "%");
    
    Токен = "AgAAAAA3EqYMAAXWQ1YuubMsO0MVvWA-nd5nVPg";
    
    ТекстЗапроса = "https://cloud-api.yandex.net/v1/disk/resources/upload? path=" + ИмяФайла_ + " & overwrite=true";
    
    httpЗапрос = Новый HTTPЗапрос(ТекстЗапроса);
    
    Ответ = Соединение.ВызватьHTTPМетод("GET", httpЗапрос);

Выдаёт ошибку
Ответ = Соединение.ВызватьHTTPМетод("GET", httpЗапрос);
по причине:
Ошибка работы с Интернет:  Не могу установить соединение
7 dka80
 
22.08.19
17:11
Ресурс = "bot" + Объект.Токен + "/sendMessage?chat_id=" + СтрЗаменить(Формат(chat_id, "ЧДЦ=; ЧС=; ЧРГ=."), ".", "") + "&text=" + ТекстОшибки;
            Соединение  =  Новый HTTPСоединение(Объект.Сервер,443,,,,,Новый ЗащищенноеСоединениеOpenSSL());
            Запрос = Новый HTTPЗапрос(Ресурс);
            Ответ = Соединение.Получить(Запрос);

только в переменную ресурс правильно подставь значение из (2)
8 dezss
 
22.08.19
17:14
(6)Соединение = Новый HTTPСоединение("cloud-api.yandex.net", ,"Логин", "Пароль",,,Новый ЗащищенноеСоединениеOpenSSL);
ТекстЗапроса = "/v1/disk/resources/upload? path=" + ИмяФайла_ + " & overwrite=true";

И в httpЗапрос = Новый HTTPЗапрос(ТекстЗапроса); установи заголовки, если они нужны.
9 dezss
 
22.08.19
17:15
(8) + Лишние пробелы убирай нафиг
ТекстЗапроса = "/v1/disk/resources/upload?path=" + ИмяФайла_ + "&overwrite=true";
10 dezss
 
22.08.19
17:18
+ потом сразу делаешь PUT, по полученному ответу из доки (аналогичным образом, только httpСоединение и httpЗапрос переделай на другой путь, на тот, что придет в ответе). Ну а потом publish аналогичным образом.
11 yurii-syrkin
 
22.08.19
17:21
Пока не врубился куда токен вставлять. В документации в формате запросов смотрю он не участвует. Я так понял это

"Ресурс = "bot" + Объект.Токен + "/sendMessage?chat_id=" + СтрЗаменить(Формат(chat_id, "ЧДЦ=; ЧС=; ЧРГ=."), ".", "") + "&text=" + ТекстОшибки;"

вообще из другой темы?
12 dezss
 
22.08.19
17:22
(11) Да, это обращение к боту телеграмма.
Токен, скорей всего, нужен в заголовках. Сча доку гляну.
13 dezss
 
22.08.19
17:25
(12) +
Полученный токен следует передавать в заголовке Authorization при каждом вызове API Диска, указывая тип токена перед его значением. Пример такого заголовка:
Authorization: OAuth 0c4181a7c2cf4521964a72ff57a34a07

И не забывай:
Корректные заголовки Accept и Content-Type: API Диска поддерживает только один MIME-тип, application/json. Любое другое значение приведет к ошибке формата данных.

Так что добавляй еще один заголовок
Content-Type: application/json
14 dezss
 
22.08.19
17:27
Предвосхищая вопрос о том, куда и как пихать эти заголовки, а то через 3 минуты ухожу домой)
Заголовки = Новый Соответсвие;
Заголовки.Вставить("Authorization","OAuth 0c4181a7c2cf4521964a72ff57a34a07");
Заголовки.Вставить("Content-Type","application/json");
httpЗапрос = Новый HTTPЗапрос(ТекстЗапроса,Заголовки);
15 yurii-syrkin
 
22.08.19
17:45
Понимаю, что туплю, но всё же. Пишу следующий код

        Соединение = Новый HTTPСоединение("cloud-api.yandex.net", ,"Логин", "Пароль");
    
    ИмяФайла_ = СтрЗаменить(ИмяФайла, "\", "%");
    
    Токен = "Это_токен_29020цдаопыавщп2952";
    
    ТекстЗапроса = "https://cloud-api.yandex.net/v1/disk/resources/upload?path="; + ИмяФайла_ + "&overwrite=true";
            
    Заголовки = Новый Соответствие;
    Заголовки.Вставить("Authorization","OAuth " + Токен);
    Заголовки.Вставить("Content-Type","application/json");
    httpЗапрос = Новый HTTPЗапрос(ТекстЗапроса, Заголовки);
        
    Ответ = Соединение.Получить(httpЗапрос);

На последней строке висит секунд 30 и вылетает с ошибкой

Ошибка при вызове метода контекста (Получить)
    Ответ = Соединение.Получить(httpЗапрос);
по причине:
Ошибка работы с Интернет:  Не могу установить соединение
16 gSha
 
22.08.19
17:53
Процедура Тест()
    Host = "https://webdav.yandex.ru:443/";;

    Cat = "Test";
    Если  спзжКаталог(Cat) = "" тогда
        
            xhr = Новый COMОбъект("Microsoft.XMLHTTP"); // 'CreateObject("WinHttp.WinHttpRequest.5.1")
            xhr.Open("MKCOL", urlencode(Host + Cat), False);
            xhr.setRequestHeader("Authorization", "Basic " + Token());
            //xhr.setRequestHeader("Authorization", "Basic " + Токен);
            xhr.send();

        Если  xhr.Status <> 201 тогда
            Сообщить(Строка(xhr.StatusText)+" "+Строка(xhr.Status));
            Возврат;
        КонецЕсли;

    КонецЕсли;    

        FileN = "ReadMeTradeWareEPF.txt";
        FileN = СтрЗаменить(FileN, "/", "_");
        avFiles = "C:\Обрезание\ReadMeTradeWareEPF.txt";
       UploadFile(FileN, avFiles, Cat);
    hlink = Public_url(FileN, Cat);
Если  hlink = "" Then
Сообщить("ВНИМАНИЕ! НЕТ ССЫЛКИ");
Иначе
Сообщить(hlink);
КонецЕсли;
КонецПроцедуры

Функция спзжКаталог(RemotePath)
Перем sReq;
Перем FileContents;
Перем FileName;


Host = "https://webdav.yandex.ru:443/";;


Catalog = "";
sReq = "";
sReq = sReq + "<propfind xmlns='DAV:'> ";
sReq = sReq + "<allprop/>";
sReq = sReq + "</propfind>";

Catalog = "";


RemotePath = ?(RemotePath <> "", RemotePath + "/", "");
    
xhr = Новый COMОбъект("Microsoft.XMLHTTP"); //'CreateObject("WinHttp.WinHttpRequest.5.1")
xhr.Open("PROPFIND", urlencode(Host + RemotePath), False);
xhr.setRequestHeader("Depth", "0");
xhr.setRequestHeader("Authorization", "Basic " + Token());
xhr.setRequestHeader("Content-Length", "158");

xhr.send(sReq);
        
        
oResponseDoc = xhr.responseXML();

oNodeList = oResponseDoc.getElementsByTagName("d:status");

Для Каждого elem из  oNodeList цикл
   Catalog = elem.Text;

КонецЦикла;

Возврат Catalog;
КонецФункции

&НаКлиенте
Function Token()

  
       Логин = "указать";
    Пароль = "указать";

    
    //Пишем его в файл, чтобы потом закодировать

    ИмяФайлаТокен = ПолучитьИмяВременногоФайла();
    ФайлТокен = Новый ЗаписьТекста(ИмяФайлаТокен,"windows-1251");
    ФайлТокен.Записать(Логин+":"+Пароль);
    ФайлТокен.Закрыть();

    

    // Кодируем пароль в Base64

    ДвоичныйТокен = Новый ДвоичныеДанные(ИмяФайлаТокен);
    Токен = Base64Строка(ДвоичныйТокен);
    //и удаляем временный файл
    УдалитьФайлы(ИмяФайлаТокен);

    Возврат Токен;
КонецФункции

&НаСервере
Функция urlencode(url)

// к великому сожалению с русскими буквами не разобрался
     Возврат url;

КонецФункции
17 gSha
 
22.08.19
17:57
НаКлиенте
Функция Public_url(LocalFilePath, RemotePath)
Перем  sReq;
Перем FileContents , FileName;

sReq = "";
Public_url = "";
Host = "https://webdav.yandex.ru:443/";;


      sReq = sReq + "<propertyupdate xmlns='DAV:'> ";
    sReq = sReq + "<set><prop>";
    sReq = sReq + "<public_url xmlns='urn:yandex:disk:meta'>true</public_url>";
    sReq = sReq + "</prop></set>" ;
    sReq = sReq + "</propertyupdate>" ;
    
  
    FileName = LocalFilePath ; //'Replace(FileName, "/", "_")
    xhr = Новый COMОбъект("Microsoft.XMLHTTP"); // 'CreateObject("WinHttp.WinHttpRequest.5.1")
        xhr.Open("PROPPATCH", urlencode(Host + RemotePath + FileName), False);
        xhr.setRequestHeader("Host", "webdav.yandex.ru");
        xhr.setRequestHeader("Authorization", "Basic " + Token());
        xhr.setRequestHeader("Content-Length", "158");
        xhr.setRequestHeader("User-Agent", "my_application/0.0.1");
        xhr.send (sReq);
        
        Если  xhr.Status <> 207 тогда
        Сообщить(Строка(xhr.StatusText)+" "+Строка(xhr.Status));

        Иначе
        oResponseDoc = xhr.responseXML();
    
        oNodeList = oResponseDoc.getElementsByTagName("d:prop"); // 'd:response
    Для  Каждого elem из oNodeList цикл

                    Public_url = elem.Text
                                

            
        КонецЦикла;
    КонецЕсли;
    
      
    
Возврат  Public_url;
КонецФункции
18 big
 
23.08.19
05:45
Вот здесь один хороший человек всё сделал и в открытый доступ выложил. )

https://github.com/vpozdnyakov/YandexDiskExchangeXML
19 dezss
 
23.08.19
08:28
(15) А вот это ты не заметил?
Соединение = Новый HTTPСоединение("cloud-api.yandex.net", ,"Логин", "Пароль",,,Новый ЗащищенноеСоединениеOpenSSL);
Обращаю внимание! Новый ЗащищенноеСоединениеOpenSSL!!!
Там обмен идет по https,а не http. Поэтому нужно именно защищенное соединение.
И, кстати, не факт что нужны логин и пароль. Так что попробуй и с ними, и без них
20 dezss
 
23.08.19
08:33
(16) (17) Вот не понимаю, зачем пользоваться чем-то сторонним, если можно использовать стандартный функционал 1С?
21 dezss
 
23.08.19
08:40
Судя по (18) логин и пароль не нужны.
Только токен.
22 yurii-syrkin
 
23.08.19
15:17
Ещё раз здравствуйте. Пишу вот такой код

Соединение = Новый HTTPСоединение("cloud-api.yandex.net",,,,,,Новый ЗащищенноеСоединениеOpenSSL);
КодID = "27db1ea35468689efe016ae754683b";
файл = "C:/date.xml";
ТекстЗапроса = "/v1/disk/resources/upload?path=" + файл;
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type","application/json");
Заголовки.Вставить("Authorization","OAuth AgAAAAввAXWQ1YuubMsO0MVvWA-nd5565Pg");
httpЗапрос = Новый HTTPЗапрос(ТекстЗапроса, Заголовки);
Ответ = Соединение.Получить(httpЗапрос);

В ответе ошибка 400
23 eklmn
 
гуру
23.08.19
15:53
(22) что такое файл?
в каком виде покажи
24 ptiz
 
23.08.19
16:07
(22) ТекстЗапроса = "/v1/disk/resources/upload";

СтруктураЗапроса = Новый Структура;
СтруктураЗапроса.Вставить("path", файл);

...
httpЗапрос.УстановитьТелоИзСтроки(ЗаписатьJSONСтроку(СтруктураЗапроса));



ну и:

Функция ЗаписатьJSONСтроку(Структура) Экспорт

    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, Структура);
    Стр = ЗаписьJSON.Закрыть();
    
    Возврат Стр;

КонецФункции // ЗаписатьJSONСтроку()
25 hhhh
 
23.08.19
16:07
(22) почему C:/date.xml  ?? Это же дикость, помещать файл в корень диска С.
26 dezss
 
23.08.19
16:09
(22)  ? path=<путь, по которому следует загрузить файл>
Это путь на яндекс-диске, а не на локальном компе. Этот метод вернет тебе ссылку, куда надо будет следующим методом грузить сам файл
27 ptiz
 
23.08.19
16:11
+(24) ой, у тебя ж get
тогда вообще УстановитьТелоИзСтроки() не надо
28 dezss
 
23.08.19
16:17
(27) Он делает как надо, только в файл запихал не то, что нужно)
29 gSha
 
23.08.19
16:52
(19) потому что для меня это все набор бесмысленного текста. Просто в моем случае файл загружается. А в вашем вы так до финала не дошли еще.
30 dezss
 
23.08.19
16:59
(29) Это ответ на (20), я так понимаю&
В моем случае все работает. Это у ТС никак не получается.
31 yurii-syrkin
 
23.08.19
17:16
Итак, коллеги разобрался. Вот код

Функция РазделитьURL(Знач URL)
    
    ИмяСервера = "";
    Путь = "";
    Протокол = "";
    Порт = 443;
    
    URL = СокрЛП(URL);
    
    Если Лев(URL, 7) = "http://"; Тогда
        URL = Прав(URL, СтрДлина(URL) - 7);
        Протокол = "http";
    ИначеЕсли Лев(URL, 8) = "https://"; Тогда
        URL = Прав(URL, СтрДлина(URL) - 8);
        Протокол = "https";
    КонецЕсли;

    Индекс = СтрНайти(URL, "/");
    Если Индекс Тогда
        ИмяСервера = Лев(URL, Индекс - 1);
        Путь = Сред(URL, Индекс);
    КонецЕсли;
    
    Индекс = СтрНайти(ИмяСервера, ":");
    Если Индекс Тогда
        Порт = Число(Сред(ИмяСервера, Индекс + 1));
        ИмяСервера = Лев(ИмяСервера, Индекс - 1);
    КонецЕсли;
    
    Результат = Новый Структура;
    Результат.Вставить("ИмяСервера", ИмяСервера);
    Результат.Вставить("Путь", Путь);
    Результат.Вставить("Протокол", Протокол);
    Результат.Вставить("Порт", Порт);
    
    Возврат Результат;
    
КонецФункции

Функция ПолучитьСсылкуНаСкачивание(ИмяФайла)

// 1. Получение ссылки для размещения файла на яндекс диске
    
    Файл = Новый Файл(ИмяФайла);
    ПутьКФайлуНаЯндексДиске = Файл.Имя;    
    ИмяСервера = "cloud-api.yandex.net";
    ОтносительныйURL = "/v1/disk/resources/upload?path=" + ПутьКФайлуНаЯндексДиске + "&overwrite=" + XMLСтрока(Истина);    
    Заголовки = Новый Соответствие;
    Заголовки.Вставить("Content-Type","application/json");
    Заголовки.Вставить("Authorization","OAuth ылдоарплыфарпжцфыйолващй");    
    HttpЗапрос = Новый HTTPЗапрос(ОтносительныйURL, Заголовки);    
    HttpСоединение = Новый HTTPСоединение(ИмяСервера, 443,,,,, Новый ЗащищенноеСоединениеOpenSSL);
    HttpОтвет = HttpСоединение.Получить(HTTPЗапрос);
    ТелоОтвета = HttpОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);        
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(ТелоОтвета);
    Ответ = ФабрикаXDTO.ПрочитатьJSON(Чтение);
    
    // 2. Загрузка файла на яндекс диск
    
    СтруктураURL = РазделитьURL(Ответ.href);
    HttpСоединение = Новый HTTPСоединение(СтруктураURL.ИмяСервера, СтруктураURL.Порт,,,,, Новый ЗащищенноеСоединениеOpenSSL);
    HttpЗапрос = Новый HTTPЗапрос(СтруктураURL.Путь, Заголовки);
    HttpЗапрос.УстановитьТелоИзДвоичныхДанных(новый ДвоичныеДанные(ИмяФайла));
    HttpОтвет = HttpСоединение.Записать(HTTPЗапрос);
    ТелоОтвета = HttpОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
    Если ТелоОтвета <> "" Тогда
        Чтение = Новый ЧтениеJSON;
        Чтение.УстановитьСтроку(ТелоОтвета);
        Ответ = ФабрикаXDTO.ПрочитатьJSON(Чтение);
    КонецЕсли;
    
    //ПутьКФайлуНаЯндексДиске = HttpОтвет.Заголовки.Получить("Location");
    
    // 3. получение публичной ссылки
    
    ТекстЗапроса = "/v1/disk/resources/publish?path=" + ПутьКФайлуНаЯндексДиске;
    HttpЗапрос = Новый HTTPЗапрос(ТекстЗапроса, Заголовки);
    HttpСоединение = Новый HTTPСоединение(ИмяСервера, 443,,,,, Новый ЗащищенноеСоединениеOpenSSL);
    HttpОтвет = HttpСоединение.Записать(HTTPЗапрос);
    ТелоОтвета = HttpОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);        
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(ТелоОтвета);
    Ответ = ФабрикаXDTO.ПрочитатьJSON(Чтение);    
    
    // 4. Получение метаданных файла
    ТекстЗапроса = "/v1/disk/resources?path=" + ПутьКФайлуНаЯндексДиске;
    HttpЗапрос = Новый HTTPЗапрос(ТекстЗапроса, Заголовки);    
    HttpОтвет = HttpСоединение.Получить(HTTPЗапрос);
    ТелоОтвета = HttpОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);        
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(ТелоОтвета);
    Ответ = ФабрикаXDTO.ПрочитатьJSON(Чтение);    
    Возврат Ответ.public_url;

КонецФункции

public_url это и есть ссылка для скачивания

Всем спасибо!
32 gSha
 
23.08.19
17:17
ну отлично ..
теперь я вставлю и у мекня тоже будет родными средствами  1с)
33 gSha
 
23.08.19
17:18
единственное не еще подкаталоги надо создавать в процессе
34 dezss
 
26.08.19
09:09
(31) Уточнение:
1. Новый ЗащищенноеСоединениеOpenSSL нужно только если https, иначе тужа Неопределено подставляй.
2. Вместо Ответ = ФабрикаXDTO.ПрочитатьJSON(Чтение), можно использовать просто ПрочитатьJSON(Чтение). Что будет быстрей, не проверял.
3. HttpОтвет = HttpСоединение.Получить(HTTPЗапрос) лучше обернуть в Попытку-Исключение, а то могут там ошибки выскакивать (если не смог разрешить имя сервера или не удалось установить защищенное подключение).
4. Порт указывать не нужно. 443-й будет использоваться если установлено Новый ЗащищенноеСоединениеOpenSSL, иначе 80-й (вроде).
5. Так же в HttpОтвет нужно проверять КодСостояния, а то может что-то не так с сервером и он вернул не 2хх.

Т.е. в идеальном случае работать все будет, но вот в случае каких-то нештатных ситуация или изменений у яндекса могут возникать ошибки.
А так молодец, сделал довольно неплохо. :)
AdBlock убивает бесплатный контент. 1Сергей