Итак, продолжим тему работы с сервисом Яндекс.Диск в Delphi. Кто не знает или уже забыл — ранее я уже писал про работу с API этого сервиса и даже выложил небольшой исходник, реализующий основные методы WebDAV с использованием моей любимой библиотеки Synapse. В прошлый раз я остановился на том, что реализовал в отдельном классе TWebDAVSend методы протокола WebDAV такие как PROPFIND, MKCOL и т.д. Сегодня мы с Вами немного расширим возможности этого класса и сделаем возможность скачивать и загружать файла в аккаунт Яндекс.Диска.
Открываем документацию API Яндекс.Диска, проект Delphi и приступаем к работе.
Чтение списка ресурсов
В начале немного разберемся с тем, что присылается нам в ответе на запрос методом PROPFIND. После выполнения PROPFIND сервер нам возвращает XML-файл, содержащий свойства ресурсов. При этом каждый узел с описанием свойств ресурса может содержать следующие дочерние элементы:
- d:href — путь к ресурсу
- d:propstat— содержит код статуса выполнения операции и набор индивидуальных свойств ресурса
- d:status — код статуса выполнения операции. Например, если мы будем использовать метод PROPPATCH (редактирование свойств ресурса), то этот узел поможет нам узнать прошла ли операция успешно или нет.
- d:prop— коллекция свойств ресурса
- d:creationdate — дата создания ресурса в UTC
- d:displayname — имя ресурса, которое используется для отображения в интерфейсе пользователя
- d:getcontentlength — размер ресурса в байтах. Соответственно, для коллекций это свойство всегда равно 0.
- d:getlastmodified — дата последнего изменения ресурса (по формату отличается от даты, представленной в d:creationdate)
- d:resourcetype — признак того, что ресурс является коллекцией. Если у этого узла имеется дочерний пустой узел d:collection, то ресурс является коллекцией, иначе — файлом.
Теперь допишем наш проект и сделаем так, чтобы в интерфейсе программы отображались все файлы и коллекции запрошенные методом PROPFIND. Интерфейс программы у меня теперь стал таким:
В ListView будем выводить информацию по ресурсам. В качестве заготовки будущих классов для работы с API Яндекс.Диска я создал следующие классы:
класс, хранящий информацию по ресурсу:
type TWDResource = class private FHref : string; FStatusCode : integer; FContentLength: int64; FCreationDate : TDateTime; FLastmodified : TDateTime; FDisplayName : string; FContentType : string; FCollection : Boolean; public property StatusCode : integer read FStatusCode; property ContentLength: int64 read FContentLength; property CreationDate : TDateTime read FCreationDate; property Lastmodified : TDateTime read FLastmodified; property DisplayName : string read FDisplayName; property ContentType : string read FContentType; property Href: string read FHref; property Collection : Boolean read FCollection; end;
Потом в этот класс можно будет добавить методы для редактирования свойств и т.д. Пока же он у нас будет выполнять одну простую роль — хранить информацию по одному ресурсу.
Следующий класс — коллекция (список ресурсов) аккаунта:
TWDResourceList = class(TList) public constructor Create; destructor Destroy;override; procedure Clear; end;
Здесь, вроде бы, тоже ничего сверхсложного нету — класс хранит список всех запрошенных ранее ресурсов и, по необходимости — чистит список.
Теперь приступим к работе с API и напишем обработчик OnClick кнопки «Выполнить» следующим образом:
procedure TForm5.Button1Click(Sender: TObject); procedure ParseResources(const AXMLStr: string); var XMLDoc: IXMLDocument; ResponseNode,ChildNode,PropNodeChild, PropertyNode: IXMLNode; s, su,Value: string; begin XMLDoc:=TXMLDocument.Create(nil); try XMLDoc.LoadFromXML(AXMLStr); if not XMLDoc.IsEmptyDoc then begin ResponseNode:=XMLDoc.DocumentElement.ChildNodes.First; while Assigned(ResponseNode) do begin Resources.Add(TWDResource.Create); ChildNode:=ResponseNode.ChildNodes.First; while Assigned(ChildNode) do begin if ChildNode.NodeName='d:href' then Resources.Last.FHref:=ChildNode.Text else if ChildNode.NodeName='d:propstat' then begin PropNodeChild:=ChildNode.ChildNodes.First; while Assigned(PropNodeChild) do begin if PropNodeChild.NodeName='d:status' then begin Value:=PropNodeChild.Text; s := Trim(SeparateRight(Value, ' ')); su := Trim(SeparateLeft(s, ' ')); Resources.Last.FStatusCode:=StrToIntDef(su, 0); end else if PropNodeChild.NodeName='d:prop' then begin PropertyNode:=PropNodeChild.ChildNodes.First; while Assigned(PropertyNode) do begin if PropertyNode.NodeName='d:creationdate' then Resources.Last.FCreationDate:=UTCToSystemTime(ISODateTime2UTC(PropertyNode.Text)) else if PropertyNode.NodeName='d:displayname' then Resources.Last.FDisplayName:=Utf8ToAnsi(PropertyNode.Text) else if PropertyNode.NodeName='d:getcontentlength' then Resources.Last.FContentLength:=PropertyNode.NodeValue else if PropertyNode.NodeName='d:getlastmodified' then Resources.Last.FLastmodified:=DecodeRfcDateTime(PropertyNode.Text) else if PropertyNode.NodeName='d:resourcetype' then Resources.Last.FCollection:=PropertyNode.ChildNodes.Count>0; PropertyNode:=PropertyNode.NextSibling; end; end; PropNodeChild:=PropNodeChild.NextSibling; end; end; ChildNode:=ChildNode.NextSibling; end; ResponseNode:=ResponseNode.NextSibling; end; end; finally XMLDoc:=nil; end; end; var Str: string; I: Integer; begin WebDAV.Login := Edit1.Text; WebDAV.Password := Edit2.Text; Resources.Clear; Str:=WebDAV.PROPFIND(1, InputBox('Ресурс', 'Ресурс', '')); if Length(Trim(Str))>0 then begin ParseResources(Str); for I := 0 to Resources.Count-1 do begin with ListView1.Items.Add do begin Caption:=Resources[i].DisplayName; SubItems.Add(Resources[i].Href); SubItems.Add(DateTimeToStr(Resources[i].CreationDate)); SubItems.Add(DateTimeToStr(Resources[i].Lastmodified)); SubItems.Add(IntToStr(Resources[i].ContentLength)); if Resources[i].Collection then SubItems.Add('yes') else SubItems.Add('no'); SubItems.Add(IntToStr(Resources[i].StatusCode)) end; end; end; end;
Выглядит довольно жутенько, поэтому рассмотрим этот метод по частям. Начнем с основного кода процедуры. Вначале мы записываем логин/пароль пользователя и запрашиваем методом PROPFIND сведения по ресурсу, который пользователь задаст в InputBox:
WebDAV.Login := Edit1.Text; WebDAV.Password := Edit2.Text; Resources.Clear; Str:=WebDAV.PROPFIND(1, InputBox('Ресурс', 'Ресурс', ''));
Если запрос прошел успешно и сервер вернул нам ответ, то выполняется вложенная процедура ParseResources, которая и разбирает XML-документ. Сама процедура хоть и выглядит немного громоздко, но является довольно простой — проходит последовательно по всем узлам XML и считывает информацию по ресурсам. Если Вам трудно разобраться с тем, что делает ParseResources, то ниже я представил Вам листинг этой процедуры с некоторыми комментариями к коду:
procedure ParseResources(const AXMLStr: string); var XMLDoc: IXMLDocument; ResponseNode,ChildNode,PropNodeChild, PropertyNode: IXMLNode; s, su,Value: string; begin XMLDoc:=TXMLDocument.Create(nil); try XMLDoc.LoadFromXML(AXMLStr); if not XMLDoc.IsEmptyDoc then begin //выбираем первый узел d:response ResponseNode:=XMLDoc.DocumentElement.ChildNodes.First; while Assigned(ResponseNode) do begin //создаем запись нового ресурса в списке Resources.Add(TWDResource.Create); //проходим по дочерним узлам d:response ChildNode:=ResponseNode.ChildNodes.First; while Assigned(ChildNode) do begin if ChildNode.NodeName='d:href' then Resources.Last.FHref:=ChildNode.Text else //нашли узел со свойствами ресурса if ChildNode.NodeName='d:propstat' then begin //выбираем первый дочерний узел, обычно - это d:status PropNodeChild:=ChildNode.ChildNodes.First; while Assigned(PropNodeChild) do begin //считываем код статуса if PropNodeChild.NodeName='d:status' then begin Value:=PropNodeChild.Text; s := Trim(SeparateRight(Value, ' ')); su := Trim(SeparateLeft(s, ' ')); Resources.Last.FStatusCode:=StrToIntDef(su, 0); end else //нашли узел d:prop - проходимся по его дочерним узлам if PropNodeChild.NodeName='d:prop' then begin PropertyNode:=PropNodeChild.ChildNodes.First; while Assigned(PropertyNode) do begin if PropertyNode.NodeName='d:creationdate' then Resources.Last.FCreationDate:=UTCToSystemTime(ISODateTime2UTC(PropertyNode.Text)) else if PropertyNode.NodeName='d:displayname' then Resources.Last.FDisplayName:=Utf8ToAnsi(PropertyNode.Text) else if PropertyNode.NodeName='d:getcontentlength' then Resources.Last.FContentLength:=PropertyNode.NodeValue else if PropertyNode.NodeName='d:getlastmodified' then Resources.Last.FLastmodified:=DecodeRfcDateTime(PropertyNode.Text) else if PropertyNode.NodeName='d:resourcetype' then Resources.Last.FCollection:=PropertyNode.ChildNodes.Count>0; //выбираем следующий дочерний узел у d:prop PropertyNode:=PropertyNode.NextSibling; end; end; //выбираем следующий дочерний узел у d:propstat PropNodeChild:=PropNodeChild.NextSibling; end; end; //выбираем следующий дочерний узел у d:response ChildNode:=ChildNode.NextSibling; end; //выбираем следующий узел d:response ResponseNode:=ResponseNode.NextSibling; end; end; finally XMLDoc:=nil; end; end;
После того, как список ресурсов заполнен снова возвращаемся в основной код процедуры OnClick и заполняем ListView данными:
for I := 0 to Resources.Count-1 do begin with ListView1.Items.Add do begin Caption:=Resources[i].DisplayName; SubItems.Add(Resources[i].Href); SubItems.Add(DateTimeToStr(Resources[i].CreationDate)); SubItems.Add(DateTimeToStr(Resources[i].Lastmodified)); SubItems.Add(IntToStr(Resources[i].ContentLength)); if Resources[i].Collection then SubItems.Add('yes') else SubItems.Add('no'); SubItems.Add(IntToStr(Resources[i].StatusCode)) end; end;
Подобным образом вы можете организовать, например, проход по всему дереву каталогов в аккаунте, запрашивая методом PROPFIND необходимые сведения. Теперь посмотрим как скачивать файлы из аккаунта.
Скачивание файлов с Яндекс.Диска
Вначале посмотрим, что нам говорит документация по поводу метода GET. В принципе тут нет ничего нового по сравнению с обычным GET, который мы уже сто раз использовали в самых разным ситуациях при работе с другими API. Яндекс.Диск также может вернуть нам файл в сжатом виде, если сжатие оправдано (про работу с GZIP я писал в статье «Используем GZip в Synapse.«). Сегодня мы рассмотрим скачивание без использование сжатия.
Дописываем у класса TWebDAVSend следующий метод:
type TWebDAVSend = class private FHTTP: THTTPSend; [...] public [...] function Get(const ElementHref:string; var Response:TStream):boolean; end; function TWebDAVSend.Get(const ElementHref: string; var Response:TStream): boolean; var URL: string; begin if not Assigned(Response) then Exit; URL:=GetRequestURL(ElementHref,false); with FHTTP do begin Headers.Clear; Document.Clear; Headers.Add('Authorization: Basic ' + FToken); Headers.Add('Accept: */*'); if HTTPMethod('GET', URL) then begin Result:=ResultCode=200; if not Result then raise Exception.Create(IntToStr(ResultCode)+' '+ResultString) else Document.SaveToStream(Response); end else raise Exception.Create(rsPropfindError+' '+ResultString); end; end;
Метод работает следующим образом: в качестве входных параметров Get принимает путь к ресурсу и поток, в который необходимо поместить скачанные данные. Здесь следует отметить, что ElementHref — это строка, которую мы только что получили из XML, когда парсили список ресурсов (свойство Href). Вначале собирается URL по которому находится файл, затем добавляются заголовки авторизации и выполнятся обычный Get. Если запрос выполнен успешно, то все данные сохраняются в поток Response. Вот и вся работа по скачиванию файлов с Яндекс.Диска :) Осталось проверить эту работу на практике.
Для проверки работы функции скачивания файла с Яндекс.Диска я написал следующий обработчик двойного клика в ListView:
procedure TForm5.ListView1DblClick(Sender: TObject); var Res:TWDResource; Stream:TStream; begin if ListView1.ItemIndex>-1 then Res:=Resources[ListView1.ItemIndex];//получили ресурс из списка Stream:=TMemoryStream.Create; try if WebDAV.Get(Res.Href,Stream) then //запрос Get прошел успешно TMemoryStream(Stream).SaveToFile(ExtractFilePath(Application.ExeName)+Res.DisplayName); finally Stream.Free; end; end;
Вид работающего приложения представлен на рисунке ниже:
Осталось только добавить, что если Вы попробуете скачать не файл, а коллекцию, то сервер вполне справедливо ругнется вот такой ошибкой:
Так что даже не пробуйте качать коллекции — только файлы. Вот и всё, что касается темы сегодняшней статьи.
Книжная полка
Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
|
||
Название: О чем не пишут в книгах по Delphi
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
|
Извиняюсь за дублирование сообщения, но без форматирования читать не возможно.
Нет ни чего менее масштабируемого, чем множество вложеных if’ов.
Условия везде одинаковые, поэтому можно разбить «if-Ёлочку» на две части:
1. Поиск в массиве возможных значений.
2. Индекс найденого элемента использовать в качестве аргумента для CASE.
Как-то так:
[code]
ValueIndex := -1;
for I=0 to High(Values) do begin
if not SameText(PropertyNode.NodeName, Values[I]) then Continue;
ValueIndex := I;
break;
end;
case ValueIndex of
0: Resources.Last.FCreationDate:=UTCToSystemTime(ISODateTime2UTC(PropertyNode.Text));
1: Resources.Last.FDisplayName:=Utf8ToAnsi(PropertyNode.Text);
2: Resources.Last.FContentLength:=PropertyNode.NodeValue;
// и т.д.
end;
[/code]
Это решение универсальное (для однотипных условий) и легко масшабируется.
Конструкция «if … then … else if …» немножко стремно выглядит.
У меня на этой строке:
Resources.Last.FHref:=ChildNode.Text
дает ошибку «[DCC Error] Unit1.pas(680): E2018 Record, object or class type required»
Что не так?
Чем можно заменить TMemoryStream для скачки больших файлов?
Дмитрий Яковлев, TFileStream?
Пример?
С вами познаю Delphi
Я так понимаю, что с помощью Synapse нельзя реализовать получение файлов больших объемов?
Необходимо переписывать сам Synapse для этого?
Дмитрий Яковлев, не правильно понимаете :) С помощью Synapse можно получать любые файлы любых объемов и не только получать, но и отправлять. И, кстати, TMemoryStream для этого подходит идеально. Вот тут можно почитать по-подробнее о THTTPSend.
Vlad, пробовал по всякому, но не выходит у меня каменный цветок :(
пробовал вместо TMemoryStream создавать TFileStream, но здесь:
WebDAV.Get(Res.Href,Stream)
в Document идет закачка файла в память, причем пытаюсь скачать файл 44 Мб, а в диспетчере задач приложение разрастается до 500 с лишним Мб и вылетает с ошибкой «Out of memory».
Издевался над Document внутри WebDAV.Get, но все равно Document «впитывает» в себя какие-то лишние мегабайты :(
Интернет, сайт и вики синапса рою уже неделю, но не нахожу решения :(
Подскажите как реализовать получение файлов большого объема средствами Synapse, пожалуйста.
Дмитрий Яковлев, ну так я же не зря ссылку дал в предыдущем комментарии :) То, что вы описываете никак не относится к Synapse..вообще никак. Утечка где-то в вашем коде. Для примера — сейчас у меня THTTPSend (тот что в Synapse) с периодичностью в 2 часа «толкает» по сети архив в 1 Гб размером. причем работа идет постоянно без перезагрузок компа и выключения программы — никаких out of memory на протяжении месяца работы и загружается все элементарно: HTTPSend.HTTPMethod('GET', URL_загрузки) Проверьте свою программку на предмет утечек — включите в ГЛАВНОМ модуле программы в секции initialization флаг ReportOnMemoryLeaksShutdown = True; и посмотрите, что… Подробнее »
В прошлом сообщении ошибся — вместо 44Мб файл размером более 700Мб.
Vlad, установил XE2, установил Synapse, скачал ваш исходник.
При скачивании большого файла приложение yandex_disk.exe разрастается пока весь файл не скачается.
Дмитрий Яковлев, ну тогда это меняет дело. Ок, Дмитрий, я посмотрю исходник, если что — отпишусь дополнительно здесь или, если будет о чем рассказать — отдельным постом. Хотя то, что приложение разрастается, в принципе, логично — файл же в память скачивается, а уже потом на диск сохраняется…Короче, разберемся :)
Vlad, разобрался с ошибкой «Out of memory» — это была Debug-версия. Не на вашем проекте, на другой простенькой програмке в строке присвоения значения переменной почему-то не работал брикпойнт, стал разбираться и выяснил, что есть Debug и Release версии. Но в Release-версии всё равно при скачивании файлов большого размера приложение увеличивается на размер скачиваемого файла. :( Я так понимаю, что при ответе от сервера (где он отсылает нам файл) мы его принимаем методом Get if WebDAV.Get(Res.Href,Stream) then //запрос Get прошел успешно с помощью Synapse в MemoryStream, наше приложение в это время зависает, а когда Synapse принял полностью, то Synapse нам его… Подробнее »
Vlad, а Вы не пробовали загружать файлы на Яндекс.Диск по их API?
Пока не пробовал. У них вроде бы API поменялся после того как я эту статью писал.
Вроде бы понял, в чём была проблема — Яндекс.Диск отказывался принимать запросы, если хотя бы раз не загрузить на него файлы вручную. Как только файлы были загружены (и увеличено пространство), сразу всё заработало как надо.
Отдельная благодарность за пример работы с WebDAV! Сам бы доходил до этого о-очень долго. Особенно с интересным поведением Яндекс.Диска при первом знакомстве :)
Антон Исаевб да не за что :) Рад, что мои поползновения в WebDAV пригодились. А вообще странно, что Янедекс.Диск себя так ведет..по идее если есть логин/пароль доступа, то на кой ещё и ручками что-то туда грузить, чтобы уже потом пользоваться API…хотя может это такая «фича» бета-версии :)
Антон, не могли бы Вы поделиться реализацией метода PUT? Второй день сижу парюсь, не могу никак сделать.
Vlad, спасибо за интересную статью, вообщем то благодаря этой статье (ну и документации самого Яндекса) получилось сделать свою программку по работе с Диском. Остался только один вопрос — а как получить статус каждого уже лежащего на Диске файла — т.е. опубликован он или нет. Читал документацию WebDav — там ни одно свойство по PROPFIND не подходит… Не подскажете, куда копать?:)
врядли подскажу. Думаю, что если такая возможность поддерживается в Яндекс.Диске, то ответ должен лежать где-то в документации..
Vlad, огромное спасибо за статью! Очень сильно помогла в моем проекте.
Столкнулся с проблемой. На моем компьютере все работает как часы. Добавляет, скачивает с Яндекс.Диск. А вот решил попробовать на другом компьютере. Приложение не работает вылетает ошибка «Ошибка при выполнении запроса PROPFIND». Пробовал подключить сетевой диск, все равно вылетает эта ошибка. Установил Яндекс.Диск проблема та же. Не подскажете в чем может быть проблема?
Спасибо.
Андрей, на сколько я помню, там ведь все запросы по httpS идут? Если да, то, по идее, надо бы рядом с exe-шником кинуть dll-ки libeay32.dll и ssleay32.dll. Качнуть можно прям с блога — вот отсюда. Сам их везде использую где есть https
Vlad, доброго времени суток. Опять я за помощью к вам и вашему уникальному ресурсу. Понадобилось считывать файлик с яндекс диска… но… на delphi 7… Вроде все победил, но вот эту строчку
TWDResourceList = class(TList)
точнее вот на это компилятор ругается… если ее убрать то он дальше по тексту ругается, типа надо укзать тип… Насколько я понимаю, эта запись означает «создать список из элементов типа «. А как такое изобразить на D7 не въезжаю… Подскажите плиз…
не ну я так не играю… почему ваш сайтик коверкает сообщения-то…
ведт потерялся ВЕСЬ сиысл вопрос из-за выбрасывания [code]"[/code]
да что же это творится, третья попытка… TWDResource
последнее слово было в
доброго времени суток. возможно ли при помощи indy или т.п. компонетов, скачать файл с я-диска по публичной ссылке?
(http://yadi.sk/d/……) и если да, то подскажите плиз как…
Одно решение в принципе понятно, но уж больно не хочется парсить страницу и пытаться добыть прямую ссыль…
skuwakin, к сожалению, без парсинга страницы здесь никак.
спасибо за оперативный ответ. Вы мне очень помогли!
Доброго времени суток. Еще один вопросик всплыл…. Не получается ни при помощи indy, ни при помощи synapse, загрузить страничку, которую выдает яндекс при попытки скачать файл с яндекс-диска. Не могут они побороть перенаправление (насколько я понял). Не подскажите как все же это осуществить? Оно конечно можно обойтись twebbrowser, но меня забодали запросы безопасности долбанного ie… и отключить это нормально у меня не получилось…
skuwakin, извините, но не поверю, чтобы ни indy, ни Synapse не могли справится с такой очевидной вещью как редирект. В Indy, на сколько я помню, достаточно установить свойство HandleRedirects в True. Synapse работает строго в соответствии с протоколом HTTP и такого свойства не имеет, но для него тоже можно создать свой аналог, например, как в этой статье
Спасибо за ответ! Буду много думать. Все проблемы. какие были (кроме редиректа) решил, да и похоже я тут с indy, synapce в принципе не прав… они для такого финта не годятся, они же javascript не исполняют… В итоге, сел за чтение API яндекса…
А как быть, если нужно только опубликовать файл?
Т.е. папку с кучей файлов пользователь сам закидывает в локальную папку ПК. Утилита Диск-Яндекс эту папку синхронизирует.
А моя программа должна только
1. Дать команду опубликовать файл (сделать его доступным для всех)
2. При этом сразу получить ссылку на опубликованный файл?
Т.е. выгружать ненужно…
Akella, сейчас Яндекс.Диск перевели на REST API (WebDAV тоже остался) и, по-моему, там был довольно простой метод публикации файлов
это оно?
https://tech.yandex.ru/disk/doc/dg/reference/publish-docpage/#publish-s
но как отправить такой PROPPATCH-запрос?
Похоже, что оно. Если бы я писал это дело на Synapse, то написал бы что-то типа такого:
HTTP: THTTPSend;
....
HTTP.Document.LoadFromStream() //загрузил в тело запроса XML
HTTP.HTTPMethod('PROPPATCH','https://webdav.yandex.ru/public_folder/readme.txt'); //отправили запрос
Но я всё-таки склоняюсь больше к вот этому варианту — https://tech.yandex.ru/disk/api/reference/publish-docpage/#publish-q
оказывается у InDy есть уже готовый модуль IdWebDAV
Причем давно. Но такого класса пока нет в Synapse
К сожалению, нет ни описания, ни примеров :(
У меня получается так:
procedure TForm2.Button1Click(Sender: TObject);
Var
s, r: TStringStream;
begin
s := TStringStream.Create(» + sLineBreak +
» + sLineBreak +
» + sLineBreak +
‘true’ + sLineBreak +
» + sLineBreak +
» + sLineBreak +
»);
r := TStringStream.Create(»);
try
IdWebDAV1.URL.Password := ‘***@yandex.ru’;
IdWebDAV1.URL.Username := ‘***’;
IdWebDAV1.URL.Port := ’80’;
IdWebDAV1.URL.URI := ‘/tst/readme.txt’;
IdWebDAV1.URL.Host := ‘webdav.yandex.ru’;
IdWebDAV1.URL.Protocol := ‘PROPFIND’;
IdWebDAV1.Put(‘https://webdav.yandex.ru/’, s, r);
Memo1.Lines.Text := r.DataString;
finally
s.Free;
r.Free;
end;
end;
не могу понять, куда вставить этот токен, который я получил от яндекса
в документации https://tech.yandex.ru/disk/doc/dg/reference/publish-docpage/#publish-s
вот он:
Authorization: OAuth 0c4182a7c2cf4521964a72ff57a34a07
токен надо отправлять в заголовках запроса. У TidHTTP это будет
idHTTP.CustomHeaders.Add('Authorization: OAuth 0c4182a7c2cf4521964a72ff57a34a07')
скорее всего и у TidWebDAV будет также само
добавил
IdWebDAV1.Request.CustomHeaders.AddValue(‘Authorization’, ‘OAuth c953e55d5ec14595ag116f33143e73b3’);
выдаёт: HTTP/1.1 401 Unauthorized.
Поменял на
IdWebDAV1.Request.Username := ‘***@yandex.ru’;
IdWebDAV1.Request.Password := ‘*******’;
IdWebDAV1.Request.Method := ‘PROPFIND’;
теперь выдаёт: HTTP/1.1 405 Method Not Allowed.
В статье ни слова о том, что это за Token?
На сайте Яндекса написано, что некий OAuth token ID нужно получать
https://tech.yandex.ru/disk/webdav/
https://tech.yandex.ru/oauth/
Самая первая ссылка в этой статье — http://www.webdelphi.ru/2012/04/synapse_webdav/ — это первая статья по WebDav Яндекс.Диска и получение токена доступа через Basic-аутентификацию. Смотрим в документацию Яндекса: Для Basic-аутентификации каждый запрос приложения к Яндекс.Диску должен содержать заголовок Authorization следующего вида: Authorization: Basic Токен доступа здесь — это строка вида логин:пароль в кодировке base64 Теперь посмотрите на свой комментарий — http://www.webdelphi.ru/2012/07/yandeks/comment-page-1/#comment-34151. Разницу ощущаете? :) Далее — кто вам сказал, что OAuth-токен вечный? У Яндекса этот токен имеет свой срок годности. Подборка статей про OAuth в блоге — http://www.webdelphi.ru/tag/oauth/ (не уверен., что все примеры в статьях будут рабочими, т.к. за пару-тройку лет сервисы могли… Подробнее »
Просто у меня не Basic утентификация.
>>OAuth-токен вечный
Ну… я думаю, что за 1-2 дня не протухнет.
>>Вы точно разбираетесь в том, что пробуете сделать?
Если бы разбирался, то вопросов бы не было. Пытаюсь разобраться.
>>Ну… я думаю, что за 1-2 дня не протухнет
Я больше скажу — OAuth-токены могут протухать за час :) И это нормально, в рамках правил протокола
За ссылки спасибо!
Ну я так понял, что если у меня есть OAuth токен, то логин/пароль можно не передавать.
Теперь дошло.
IdWebDAV1.Request.Method := 'PROPPATCH';
IdWebDAV1.Request.Host := 'webdav.yandex.ru';
IdWebDAV1.URL.URI := '/tst/readme.txt';
IdWebDAV1.URL.Host := 'webdav.yandex.ru';
IdWebDAV1.Request.Source := s;
IdWebDAV1.Request.ContentType := 'application/x-www-form-urlencoded';
IdWebDAV1.Request.CustomHeaders.Add('Authorization: OAuth c412e33d6ec24895aa116f33143e73b3');
IdWebDAV1.Post('https://oauth.yandex.ru/verification_code', s, r);
На Андроид не будет компилиться… Чем заменить ингредиенты-участники?
На Андроиде лучше использовать не WebDAV, а REST API Диска. Проще и легче
Здравствуйте. Спасибо автору за статьи. С интересом изучаю.
Подскажите по 2м вопросам:
1. Как понимать выражение типа «Result:=ResultCode=200». Я так понимаю что это присвоение с условием? Т.е. если ResultCode будет равен 200, то к Result присвоится значение 200?
2. Где нужно указать куда сохранить файл при скачивании с Яндекс.Диск? По умолчанию файл скачивается в папку с программой
Заранее спасибо
Означает, что, если ResultCode=200, то Result присвоится значение TRUE.
Путь указывается вот в этой строке.
TMemoryStream(Stream).SaveToFile(ExtractFilePath(Application.ExeName)+Res.DisplayName);
Но вообще, этот пример для скачивания файлов не совсем удачный в том плане, что используется TMemoryStream. Если решите использовать код, то лучше перепишите код на использование потока TFileStream — будет более правильно.