Иногда требуется одним POST-запросом отправить на сервер несколько разных по составу и содержанию документов. К примеру, такие действия требуются, когда Вы загружаете на сервер Google какой-либо документ, который должен содержать какую-либо мета-информацию (язык на которой необходимо перевести документ, сведения об авторе и т.д.). В этом случае ваш запрос должен одновременно содержать информацию двух типов: XML с мета-данными и данные отправляемого файла. Как это сделать рассмотрим на примере Google Documents List API.
Для работы нам понадобится компонен GoogleLogin, последнюю рабочуюю версию которого Вы можете скачать здесь и, собственно, сама библиотека Synapse. Для обработки XML воспользуемся возможностями NativeXML.
Итак, пишем маленькое приложение, которое загружает на сервер Google документ и в качестве мета-информации отправляет название документа. Размещаем на главной форме компонент GoogleLogin и несколько дополнительных компонентов как показано на рисунке:
и пишем приложение по частям.
1. Авторизация в сервисе "Документы Google"
На данный момент, используя компонент GoogleLogin узнать о результате авторизации можно только через его событие OnAutorization. Поэтому на событие OnClick кнопки "Логин" пишем:
procedure TForm6.Button1Click(Sender: TObject); begin with GoogleLogin1 do begin Email:=Edit1.Text; Password:=Edit2.Text; Service:=writely;//идентификатор сервиса гуглодоков AccountType:=atHOSTED_OR_GOOGLE; Login(); end; end;
А в обработчики события компонента проверяем результат (без обработки каптчи):
procedure TForm6.GoogleLogin1Autorization(const LoginResult: TLoginResult; Result: TResultRec); begin if LoginResult=lrOk then Edit3.Text:=Result.Auth else Edit3.Text:=Result.LoginStr; Button2.Enabled:=LoginResult=lrOk; Button3.Enabled:=LoginResult=lrOk; end;
После того, как авторизация получена можно отправлять документ на сервер.
2. Формирование запроса и его отправка
Вначале напишем код, который будет составлять XML-документ. Документ должен быть следующего содержания:
<code> <?xml version='1.0' encoding='UTF-8'?> <entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005"> <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document"/> <title>%s</title> </entry> </code>
Так как изменяться в документе будет всего одна строка - содержимое тега Title, то я просто сохранил этот документ в файл xml.txt и буду этот файл при необходимости изменять. В итоге для составления правильного XML-содержимого запроса сделать необходимо не так уж и много:
var Form6: TForm6; XMLStream: TMemoryStream;; ... procedure TForm6.FormCreate(Sender: TObject); begin XMLStream:=TMemoryStream.Create; end; function TForm6.GetXML(const DocTitle: string): string; begin var XMLDoc: TNativeXML; begin XMLStream.Clear;//очистили поток XMLDoc:=TNativeXML.Create; XMLDoc.LoadFromFile(ExtractFilePath(Application.ExeName)+'xml.txt'); XMLDoc.Root.NodeByName('title').ValueAsString:=Edit5.Text;//замненили название документа XMLDoc.SaveToStream(XMLStream);//сохранили данные в поток FreeAndNil(XMLDoc); end; procedure TForm6.FormDestroy(Sender: TObject); begin FreeAndNil(XMLStream) end;
Теперь составляем запрос и осуществляем отправку запроса. Для этого подключаем в uses модуль httpsend:
procedure TForm6.Button3Click(Sender: TObject); Const CR = #$0d; LF = #$0a; CRLF = CR + LF; var HTTP: THTTPSend; S:AnsiString; FS: TFileStream; begin //получили XML GetXML(Edit5.Text); HTTP:=THTTPSend.Create; //вставляем заголовки авторизации HTTP.Headers.Add('GData-Version: 3.0'); HTTP.Headers.Add('Authorization: GoogleLogin auth='+Edit3.Text); //определяем тип данных HTTP.MimeType:='multipart/related; boundary=END_OF_PART'; HTTP.Headers.Add('Slug: '+EncodeURLElement(ExtractFileName(Edit4.Text))); {составляем тело запроса} S:='--END_OF_PART'+CRLF; //MIME-тип первой части документа S:=S+'Content-Type: application/atom+xml'+CRLF+CRLF; HTTP.Document.Write(PAnsiChar(S)^, Length(S));//записали строку //пишем в Document содержимое XML XMLStream.Position:=0; HTTP.Document.CopyFrom(XMLStream,XMLStream.Size); S:=CRLF+CRLF+'--END_OF_PART'+CRLF;//первая часть документа закончена {вторая часть - документ *.doc} S:=S+'Content-Type: application/msword'+CRLF+CRLF; HTTP.Document.Write(PAnsiChar(S)^, Length(S));//записали строку {записываем doc-файл} FS:=TFileStream.Create(Edit4.Text,fmOpenRead); FS.Position:=0; HTTP.Document.CopyFrom(FS,FS.Size); FreeAndNil(FS); {завершаем тело запроса} s := CRLF + '--END_OF_PART--' + CRLF; HTTP.Document.Write(PAnsiChar(S)^, Length(S));//завершили тело документа //Отправляем запрос if HTTP.HTTPMethod('POST','http://docs.google.com/feeds/default/private/full') then ShowMessage(HTTP.ResultString); end;
В этой процедуре мы загружаем в Document (TMemoryStream) данный из двух потоков, разделяя каждую часть специальным разделителем, который, кстати сказать, может быть не только такой как показано в примере. Если отправка завершилась успешно, то в результате выполнения процедуры мы получим сообщение с текстом "201 Created" - документ успешно отправлен и создан на сервере Google.
Исходники приложения можно скачать здесь.
--------------------------------------------------------------
Продолжение бесплатной акции.
И за вчерашний день самым продуктивным блогом оказался блог "Delphi 2010". Если Вас интересуют компоненты DevExpress, причём не просто рекламная информация о том какие они замечательные, а именно трезвая оценка их работы на примерах их практического использования, то предлагаю Вам ознакомится с целой серией постов, посвященных теме использования DevExpress в Delphi.
--------------------------------------------------------------
Смотрели сериал "Черная метка"? Если он вам понравился, то можете заглянуть на фан-сайт этого сериала - burn-notice.ru
------------------------------------------------------------
| Делись! | Загружай! | Плюсуй! |
| | |










26 Авг 2010 в 2:29 дп
А нету ли у Вас примера как отправить файл на определенный сайт (FTP наверное). То есть указать хост, пароль, логин, порт… В примерах, идущими вместе с Synapse так и не разобрался. С получением файла проблем нет, а вот с отправкой, пока не понятно.
26 Авг 2010 в 2:40 дп
Pavel, сорри, нос FTP в Synapse не работал никогда. Как-то не довелось. Если будет необходимость работы с FTP, то в блоге вы эту работу увидите :)