(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
Enterprise Connectors (1 Year term)
Delphi Professional Named User
erwin Data Modeler Navigator Edition r9.7 - Product plus 1 Year Enterprise Maintenance Commercial
ABViewer Professional пользовательская
VMware Workstation 14 Player for Linux and Windows, ESD
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Утиль - лучший бесплатный софт для Windows
ЕRP-Форум. Творческие дискуссии о системах автоматизации
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100