(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Synapse: работа с WebDAV на примере Яндекс.Диска.

Источник: webdelphi
webdelphi

Недавно Яндекс объявил о запуске свого облачного сервиса под названием Яндекс.Диск. А буквально пару дней назад и Google запустил свой Google Drive.  У меня была возможность поработать с обоими этими сервисами и оценить их удобство/полезность для себя. Надо сказать, что при выборе тех или иных онлайн-сервисов я, обычно, выбирал сервисы от Google (Календарь, Почта, соц.сеть и т.д.), но в случае с облачными сервисами я пока больше склоняюсь к использованию сервиса от Яндекс. По большей части такой выбор был сделан на основе изучения двух документов: API Яндекс.Диска и SDK Google Drive. Google в очередной раз "порадовал" ограничениями на использование API и набором методов API - есть методы добавления, редактирования и получения данных по файлам, но почему-то отсутствуют методы для удаления...странно как-то.  Можно было бы привести ещё несколько причин моего выбора, но к статье эти причины не имеют никакого отношения.  Яндекс в плане API оказался более дружелюбным к разработчикам - никаких ограничений, доступ к методам через Basic- или OAuth-аутентификацию (по выбору) и никаких "наворотов" в API - только методы и возможности WebDAV. Надеюсь, что Яндекс после окончания бетта-тестов Диска не переделает API и то, что будет рассказано и показано ниже будет работать ещё долго. Итак, сегодня продолжим речь о замечательной библиотеке Synapse и посмотрим как можно работать с протоколом WebDAV на примере API Яндекс.Диска
Что представляет из себя протокол WebDAV? Вот небольшая выдержка из Вики:

WebDAV (Web-based Distributed Authoring and Versioning) - защищённый сетевой протокол высокого уровня, работающий поверх HTTP для доступа к объектам и коллекциям.
WebDAV расширяет HTTP следующими командами:

  • PROPFIND - Получение свойств объекта на сервере в формате XML. Так же можно получать структуру репозитория (дерево каталогов).
  • PROPPATCH - Изменение свойств за одну транзакцию.
  • MKCOL - Создать коллекцию объектов (каталог в случае доступа к файлам)
  • COPY - Копирование из одного URI в другой
  • MOVE - То же что и предыдущий, только перемещение
  • LOCK - Поставить блокировку на объекте. WebDAV поддерживает эксклюзивные и общие (shared) блокировки
  • UNLOCK - Снять блокировку с ресурса

А раз WebDAV - это надстройка над HTTP(S), то нам никто не мешает использовать для этого давно уже нам известный класс THTTPSend. Все, что от нас требуется при подготовке к работе - это немного вспомнить про работу с https в Synapse, ну и, если необходимо, освежить в памяти работу с GZip. Так как WebDAV передает всю мета-информацию по документам в виде XML, то дополнительно нам может потребоваться какая-нибудь библиотека для работы с XML - обычный MSXML, NativeXML и т.д.

Примечание: если ищите быстрый парсер XML - почитайте эту статью в блоге Teran'а - там есть хорошая табличка сравнения скорости работы различных XML-парсеров

Теперь приступим к работе. Создадим в Delphi проект VCL Application, подключим в uses модули Synapse:

  • httpsend,
  • synacode,
  • ssl_openssl

И на главной форме разместим следующие компоненты (см. рисунок):

Для доступа к методам API будем использовать простую Basic-аутентификацию. Так как в каждый запрос мы должны будем вставлять заголовок аутентификации, то напишем свой небольшой класс для работы с API. В принципе, можно было бы обойтись пока и без класса, но лишним, думаю, он не будет. Итак, заготовка класса для работы с WebDAV через THTTPSend будет такой:

type
  TWebDAVSend = class
  private
    FHTTP : THTTPSend;
    FToken: AnsiString;
    FPassword: string;
    FLogin: string;
    procedure SetLogin(const Value: string);
    procedure SetPassword(const Value: string);
    procedure SetToken;
  public
    constructor Create;
    destructor Destroy; override;
    property Login: string read FLogin write SetLogin;
    property Password: string read FPassword write SetPassword;
end;
 
{ TWebDAVSend }
 
constructor TWebDAVSend.Create;
begin
  inherited;
  FHTTP:=THTTPSend.Create;
end;
 
destructor TWebDAVSend.Destroy;
begin
  FHTTP.Free;
  inherited;
end;
 
procedure TWebDAVSend.SetToken;
begin
  FToken:=EncodeBase64(FLogin+':'+FPassword);
end;
 
procedure TWebDAVSend.SetLogin(const Value: string);
begin
  FLogin := Value;
  SetToken;
end;
 
procedure TWebDAVSend.SetPassword(const Value: string);
begin
  FPassword := Value;
  SetToken;
end;

Теперь попробуем реализовать несколько методов WebDAV. Первое, что нам необходимо - это определить какие каталоги имеются в Яндекс.Диске. Для этого нам надо реализовать в классе метод API PROPFIND. Согласно документации API, набор файлов и каталогов, свойства которых должны содержаться в ответе, определяется заголовком  Depth  со следующими поддерживаемыми значениями:

  • 0 - запрашиваются свойства файла или каталога, непосредственно указанного в запросе.
  • 1 - запрашиваются свойства каталога, а также всех элементов, находящихся на первом уровне каталога.

В результате запроса сервер ответит нам XML-документом, содержащим необходимые нам свойства. Реализация PROPFIND в нашем классе будет такой:

function TWebDAVSend.PROPFIND(Depth: integer; const Element: String): string;
begin
  with FHTTP do
  begin
    Headers.Clear;
    Document.Clear;
    Headers.Add('Authorization: Basic ' + FToken);
    Headers.Add('Depth: ' + IntToStr(Depth));
    Headers.Add('Accept: */*');
    if HTTPMethod('PROPFIND', GetRequestURL(Element)) then
      result := ReadStrFromStream(Document, Document.Size)
    else
      raise Exception.Create(rsPropfindError+' '+ResultString);
  end;
end;

Рассмотрим работы этой функции. Вначале мы очищаем заголовки и тело от данных, полученных в предыдущем запросе, если таковой был. После этого вставляем заголовок аутентификации, указываем "глубину просмотра" в заголовке Depth. Затем, выполняем запрос PROPFIND на сервер и здесь вам встречается неизвестная функция GetRequestURL.
Функция GetRequestURL получает корректный URL. В качестве параметра задается любой действительный путь в дереве каталогов и файлов. К примеру, в параметре функции я могу задать такую строку:

Documents/Мои статьи/Delphi/Работа с API Яндекс.Диска.doc

И функция вернет мне URL, который гарантированно примет сервер. GetRequestURL выглядит следующим образом:

const
  cWebDAVServer = 'https://webdav.yandex.ru/';
function TWebDAVSend.GetRequestURL(const Element: string): string;
var URI: string;
begin
  URI:=Element;
  if URI[1]='/' then
    Delete(URI,1,1);
  Result:=cWebDAVServer+EncodeUTF8URI(URI);
end;

Здесь, опять же, встречается ещё одна непонятная функция - EncodeUTF8URI. Эта функция проводит кодирование URI, который может содержать символы в кодировке UTF-8. Выглядит функция так:

function TWebDAVSend.EncodeUTF8URI(const URI: string): string;
var
  i: integer;
  Char: AnsiChar;
begin
  result := '';
  for i := 1 to length(URI) do
  begin
    if not(URI[i] in URLFullSpecialChar) then
      begin
      for Char in UTF8String(URI[i]) do
        Result:=Result+'%'+IntToHex(Ord(Char), 2)
      end
    else
      Result:=Result+URI[i];
  end;
end;

URLFullSpecialChar - это множество, которое описано в модуле synacode.pas Synapse:

  URLFullSpecialChar: TSpecials = [';', '/', '?', ':', '@', '=', '&', '#', '+'];

Вполне возможно, что можно было бы как-нибудь обойтись методами Synapse типа EncodeURLElement, но для строки "Библиотека" эта функция выдавала такую строку:
%C1%E8%E1%EB%E8%EE%F2%E5%EA%E0
вместо такой:
%D0%91%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B0
поэтому я, долго не заморачиваясь, написал свою маленькую функцию кодирования. Она может и не идеальна, но сервер Яндекс.Диска отвечал правильно. Так...с чего мы начали? Ах да - с TWebDAVSend.PROPFIND. Так вот, если запрос проходит успешно, то дальше мы просто считываем строку из тела запроса (Document), а если была какая-либо ошибка - показываем её пользователю.
В результате выполнения TWebDAVSend.PROPFIND сервер может ответить следующим образом:

  • Если запрос обработан успешно - возвращается XML-документ, содержащий свойства элемента(-ов)
  • Если был задан не верный элемент, то вернется строка, содержащая описание ошибки.

Пример успешно выполненного запроса PROPFIND показан на рисунке ниже:

Пример с неправильно заданным элементом (сервер возвращает код 200 и описание ошибки):

Про метод PROPFIND стоит также добавить, что имя каталога на сервере может не совпадать с представлением этого каталога в URL. Например, каталог "Музыка" в URL представляется как "Music". Чтобы понять как должен выглядеть URL для получения свойств какого-либо каталога необходимо смотреть на свойство 'href' в XML-документе. Список всех свойств, поддерживаемых в рамках протокола WebDAV приведен в разделе описания протокола DAV Properties.

Аналогично методу PROPFIND можно реализовать и другие методы для работы с WebDAV в Synapse. Все методы рассматривать, думаю, смысла нет - алгоритм работы практически неизменный: вставили заголовки аутентификации, собрали URL, отправили запрос, обработали ответ. Но, для полноты картины, рассмотрим  ещё один метод WebDAV - MKCOL. В отличие от предыдущего, этот метод не возвращает ничего в теле ответа, а об успешности выполнения запроса можно судить по ResulCode. Итак, чтобы создать на сервере новую коллекцию, мы будем использовать в нашем классе такую функцию:

function TWebDAVSend.MKCOL(const ElementPath: string): boolean;
begin
  Result:=False;
  with FHTTP do
  begin
    Headers.Clear;
    Document.Clear;
    Headers.Add('Authorization: Basic ' + FToken);
    Headers.Add('Accept: */*');
    if HTTPMethod('MKCOL', GetRequestURL(ElementPath)) then
      begin
        Result:=ResultCode=201;
        if not Result then
          raise Exception.Create(IntToStr(ResultCode)+' '+ResultString);
      end
    else
      raise Exception.Create(rsPropfindError+' '+ResultString);
  end;
end;

Пример использования MKCOL:

MKCOL('Documents/Новая папка с документами');

В результате в каталоге Documents будет создан новый с названием "Новая папка с документами". Следует отметить, что согласно протоколу WebDAV, в результате одного запроса может быть создан только один каталог. Если приложение отправляет запрос о создании каталога a/b/c/, а в каталоге a/ нет каталога b/, то сервис не создает каталог b/, а отвечает c кодом 409 Conflict.

Вот, пожалуй, кратко о том как можно реализовать работу с WebDAV в Synapse и использовать API Яндекс.Диска в своих Delphi-приложениях. Исходник проекта, рассмотренного в статье Вы всегда сможете скачать со страницы с исходниками  (раздел по Delphi XE2) и, при необходимости, дописать реализацию других методов API.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 01.06.2012 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Delphi Professional Named User
Enterprise Connectors (1 Year term)
DevExpress / ASP.NET Subscription
Microsoft 365 Business Standard (corporate)
EMS Data Export for PostgreSQL (Business) + 1 Year Maintenance
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
Реестр Windows. Секреты работы на компьютере
СУБД Oracle "с нуля"
eManual - электронные книги и техническая документация
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100