с библиотекой Synapse я знаком достаточно давно и, вроде бы, никаких особых серьезных претензий к Synapse нет. Но, тем не менее, чего-то да не хватает. Например, не хватает автоматического редиректа при получении 301 или 302 кода, хотелось бы получить более удобную (для меня) работу с заголовками и т.д. и т.п. Снизить, так сказать, затраты времени на написание программ, использующих Synapse. Я решил для этих целей использовать свой class helper.
Во-первых, поработаем немного с заголовками. В Synapse все заголовки хранятся в виде списка TStringList. Вполне удобно, если бы не одно «НО». Но иногда часто необходимо знать:
1. Какие заголовки (названия заголовков) вообще пришли нам
2. Определить какое значение содержит тот или иной заголовок, например, HTTP-заголовок «Location».
Поэтому, начнем именно с этого — работа с заголовками.
Запускаем Delphi 2010 или Delphi XE, создаем приложение (с помощью него будем тестить хэлпер) — я буду использовать приложение для работы с Google Docs. В uses подключаем модуль httpsend.pas.
Объявляем class helper:
type THTTPSend_ = class helper for THTTPSend public function HeaderNameByIndex(index:integer):string; function HeaderByName(const HeaderName:string):string; end;
Метод HeaderNameByIndex будет возвращать название заголовка по его индексу, а второй (HeaderByName) — значение заголовка по его имени.
function THTTPSend_.HeaderNameByIndex(index: integer): string; begin if (index>(Headers.Count-1))or(index<0) then Exit; Result:=copy(Headers[index],0, pos(':',Headers[index])-1) end; function THTTPSend_.HeaderByName(const HeaderName: string): string; var i:integer; begin for i:=0 to Headers.Count-1 do begin if LowerCase(HeaderNameByIndex(i))=lowercase(HeaderName) then begin Result:=copy(Headers[i],pos(':', LowerCase(Headers[i]))+2, Length(Headers[i])-length(HeaderName)); break; end; end; end;
Теперь, когда мы можем определить значения заголовков, можно написать новый HTTPMethod, который будет, в случае получения 301 или 302 кода, делать автоматический редирект на необходимый URL:
function THTTPSend_.HTTPMethod(const Method, URL: string): Boolean; var Heads: TStringList; Cooks: TStringList; Redirect: string; Doc:TMemoryStream; begin try Heads:=TStringList.Create; Cooks:=TStringList.Create; Doc:=TMemoryStream.Create; Doc.LoadFromStream(Document); Cooks.Assign(Cookies); Heads.Assign(Headers); Result:=inherited HTTPMethod(Method,URL); if (ResultCode=301)or(ResultCode=302) then begin Redirect:=HeaderByName('location'); Headers.Assign(Heads); Document.Clear; Document.LoadFromStream(Doc); Cookies.Assign(Cooks); Result:=inherited HTTPMethod(Method,Redirect); end; finally FreeAndNil(Heads); FreeAndNil(Cooks); FreeAndNil(Doc) end; end;
Здесь мы вначале перед отправкой данных на сервер сохраняем значения Cookies, Headers и Document для того, чтобы в случае наличия редиректа не потерять эти данные (они автоматически заменяться на заголовки, куки и html-код перенаправления соответственно). Затем отправляем данные с использованием «родного» HTTPMethod и анализируем результат. Если получили код перенаправления, то определяем значение заголовка location и снова отправляем запрос.
Для бОльшей универсальности необходимо было бы сделать подсчёт редиректов и перенаправлять до тех пор пока не получим код отличный от 3хх, но мне такая универсальность не нужна, а Вы сможете дописать метод в любой момент.
var HTTP: THTTPSend; begin try HTTP:=THTTPSend.Create; if HTTP.HTTPMethod('GET','AnyURL') then begin Memo1.Lines.Add('-----------------------------'); Memo1.Lines.Add(HTTP.Headers.Text); Memo1.Lines.Add('-----------------------------'); end
Теперь можете протестировать class helper для Synapse и отправить какой-либо запрос, который 100% возвращает редирект на другую страницу. Я тестировал class helper на работе с Google Docs, а именно на скачивании документа с сервера — httpsend автоматически сделал 1 редирект и загрузил документ. Ну о загрузке гуглодоков и их конвертации в различные форматы мы поговорим позже, а пока можете скачать class helper для Synapse и протестировать его работу в своей программе:
Книжная полка
Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
|
||
Название: О чем не пишут в книгах по Delphi
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
|
Посмотрите мою реализацию
http://narod.ru/disk/25641124000/IngHTTPSend.7z.html
Метод GetParamValue по-моему проще, чем ваш HeaderByName, единственное — надо учитывать регистр.
Взамен хелперу необходимо сделать так:
constructor THTTPSend.Create;
begin
inherited;
FHeaders.NameValueSeparator := ':'; // <-- вместо хелпера
end;
А потом читать на здоровье:
Headers.Values['location']