Использование HTTP в Delphi

== Введение ==
В связи с все большим вниманием, которое привлекает к себе Интернет, все больше людей становятся заинтересованы в сетевых технологиях. Данная статья посвящена программированию на Borland Delphi с использованием одного из самых популярных Интернет-протоколов - HTTP.
А именно, здесь мы рассмотрим компонент TNMHTTP (NetMasters HTTP), который можно обнаружить на вкладке FastNet палитры компонентов Дельфи.
Начнем с теории. Если Вы уже знаете, что такое HTTP и зачем он нужен, то пропустите следующий раздел.
== Зачем нужен HTTP ==
Итак, где же используется HTTP? Если Вы хотя бы чуть-чуть заглядывали на Интернет-странички и встречались с термином Web, то наверняка обратили внимание на то, что адреса страничек, как правило, начинаются с http://. Протокол HTTP (HyperText Transfer Protocol) позволяет принимать и посылать не только гипертекстовые документы (типа html), но и любые другие (тексты (txt), изображения (gif, jpg), и т.д.). Ниже приведены типовые задачи, для выполнения которых необходимо использовать HTTP:
* Браузеры - программы, позволяющие просматривать Интернет-странички; 
* Скачивальщики - программы, позволяющие скачивать из Интернета странички, рисунки и другие документы; 
* Чаты - программы, позволяющие общаться по сети. Часто документы HTTP используются для хранения сообщений (как, например, в конференциях).
- Это лишь список некоторых из стандартных направлений программирования с использованием HTTP. Вы можете применять этот протокол для любых своих целей. Например, автоматические системы обновления данных, посылка запросов в Интернетовские базы, и еще множество всяческих других возможностей!
== Краткое описание свойств, методов и событий ==
Ниже приведена таблица, содержащая наиболее краткое описание основных свойств, методов и событий компонента TNMHTTP:
=== Свойства ===
* Body - строка, содержащая либо путь к файлу, в который будет записано тело http-документа (если св-во InputFileMode равно True), либо непосредственно само тело (если св-во InputFileMode равно False). Тип: string;
* Header - строка, содержащая либо путь к файлу, в который будет записан заголовок http-документа (если св-во InputFileMode равно True), либо непосредственно сам заголовок (если св-во InputFileMode равно False). Тип: string;
* HeaderInfo - структура, содержащая различную информацию о http-документе (подробней см. в help-файле). Тип: THeaderInfo;
* InputFileMode - тип записи результата. Значение True - запись в файлы, указанные в свойствах Body и Header, False - запись в сами эти свойства. Тип: Boolean;
* OutputFileMode - тип отсылаемых данных (методами Put, Post и Trace). Значение True - данные для отправки содержатся в файлах, указанных при вызове этих методов, а False - в самих аргументах этих методов. Тип: Boolean;
Далее некоторые свойства, унаследованные от TPowerSock:
* BytesRecvd, BytesSent, BytesTotal - количество отправленных, принятых и общее количество байтов соответственно. Тип: LongInt;
* Connected - показывает, установлено ли в данный момент соединение. Тип: Boolean;
* BeenCanceled - показывает, было ли прервано соединение с сервером. Тип: Boolean;
* Host - строка, содержащая хост-имя удаленного компьютера. Заполнять не надо, так как это свойство устанавливается автоматически при вызове методов Get, Put, Post и т.д. Тип: string. Port - Integer, содержащий порт удаленного компьютера (заполняется тоже автоматически);
* TimeOut - таймаут в миллисекундах. Тип: Integer;
Еще есть множество свойств, но я пока остановлюсь на уже перечисленных. За дополнительной информацией обращайтесь к help-у по Дельфи.
=== Методы ===
* Get(URL: string) - посылает запрос на указанный URL. Данные после выполнения этого запроса записываются в файлы или в сами свойства Body и Header (в зависимости от значения свойства InputFileMode);
* Head(URL: string) - посылает запрос на указанный URL. Данные после выполнения этого запроса записываются в файл или в само свойство Header (в зависимости от значения свойства InputFileMode). В отличие от метода Get, при вызове Head запрос отсылается только на заголовок http-документа;
* Post(URL, PostData: string) - посылает запрос на изменение http-документа (с адресом URL) на данные, содержащиеся в параметре PostData. Если OutputFileMode равен True, то в PostData должен содержаться путь к файлу, содержащему нужные данные.
* Put(URL, PutData: string) - посылает запрос на создание http-документа (с адресом URL), содержащего данные, переданные в параметре PutData. Если OutputFileMode равен True, то в PostData должен содержаться путь к файлу, содержащему нужные данные.
* Trace(URL, TraceData: string) - посылает запрос на получение отладочных данных (для отладки соединения с HTTP-сервером). Данные для запроса нужно указать в параметре TraceData. Если OutputFileMode равен True, то в TraceData должен содержаться путь к файлу, содержащему нужные данные.
* Delete(URL: string) - посылает запрос на удаление http-документа (с адресом URL).
Далее некоторые методы, унаследованные от TPowerSock:
* Abort и Cancel - прерывают соединение и обмен данными;
* Disconnect - отсоединение от HTTP-сервера;
=== События ===
* OnAuthenticationNeeded - возникает, когда сервер требует указания имени пользователя и пароля. В обработчике этого события (если оно возникнет) Вы должны ответить серверу, заполнив нужными значениями соответствующие переменные. Примечание: Перед установлением соединения можно сразу заполнить поля UserID и Password в свойстве HeaderInfo;
* OnAboutToSend - возникает, когда компонент TNMHTTP собирается отправлять данные (запрос). В обработчике этого события можно заполнить дополнительной информацией свойство SendHeader;
* OnFailure - возникает, когда текущая операция завершилась неудачно, т.е. произошла ошибка;
* OnRedirect - возникает, сервер переадресовал ссылку с указанной URL на другую ссылку. Установив параметр handled в значение True можно запретить переадресацию и остановиться на запрошенной URL. Значение по умолчанию - False;
* OnSuccess - возникает, когда текущая операция завершилась успешно, т.е. запрос был выполнен без ошибок;
Далее некоторые методы, унаследованные от TPowerSock:
* OnConnect - возникает, когда соединение с сервером успешно установлено;
* OnDisconnect - возникает, когда соединение с сервером завершено;
* OnConnectionFailed - возникает, когда соединение с сервером установить не удалось;
* OnError - возникает, когда последняя операция была завершена с ошибкой;
* OnHostResolved - возникает, когда от DNS получен IP-адрес указанного хоста;
* OnInvalidHost - возникает, когда DNS вернул ошибку при попытке определить IP-адрес указанного хоста;
* OnPacketRecvd - возникает, когда значения свойств BytesRecvd и BytesTotal изменены, т.е. была принята новая порция данных от сервера;
* OnPacketSent - возникает, когда значения свойств BytesSent и BytesTotal изменены, т.е. была отправлена новая порция данных на сервер;
* OnStatus - возникает, когда статус компонента был изменен (для обновления визуального оповещения пользователя);
== Практика и примеры ==
Ну а теперь приступим к самому главному методу изучения - на примерах. Сразу замечу, что все приведенные здесь примеры можно скачать в полностью сделанных исходниках, щелкнув здесь.
И самый первый пример - программа, позволяющая определить, существует ли заданный URL:
=== Пример 1. Проверка существования указанной URL ===
{ ... Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1 }
{В форму нужно поместить кнопку TButton и одно поле TEdit. При нажатии на кнопку вызывается обработчик события OnClick - Button1Click. Перед этим в TEdit нужно ввести адрес URL.
НЕ ЗАБУДЬТЕ ПОМЕСТИТЬ В ФОРМУ КОМПОНЕНТ TNMHTTP!}
procedure Button1Click(Sender: TObject);
begin
 { Пытаемся получить заголовок }
 NMHTTP1.Head(Edit1.Text);
 { Если URL неверный, то здесь выскочит ошибка }
end;
=== Пример 2. Скачивание указанной URL в заданный файл ===
{ ... Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1 }
{ В форму нужно поместить кнопку TButton и три поля TEdit. При нажатии на кнопку вызывается обработчик события OnClick - Button1Click. Перед этим в первый TEdit нужно ввести адрес URL, во второй - имя файла для заголовка, а в третий - имя файла для тела странички (html).
НЕ ЗАБУДЬТЕ ПОМЕСТИТЬ В ФОРМУ КОМПОНЕНТ TNMHTTP! }
procedure Button1Click(Sender: TObject);
begin
 { Пытаемся получить http-документ }
 { Результат надо записать в файлы }
 NMHTTP1.InputFileMode := True;
 { А здесь указываем в какие именно файлы }
 NMHTTP1.Header := Edit2.Text;
 NMHTTP1.Body := Edit3.Text;
 NMHTTP1.Get(Edit1.Text);
end;
=== Пример 3. Одновременное скачивание указанных URL в заданный каталог ===
{ ... Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1 }
{ Описание класса отдельного процесса }
type
 THTTPThread = class(TThread)
 private
 { Для каждого процесса - создаем свой компонент TNMHTTP }
 FHTTP: TNMHTTP;
 protected
 { Execute вызывается при запуске процесса; override - заменяем существующую процедуру базового класса TThread }
 procedure Execute; override;
 { DoWork - созданная нами функция, выполнение которой синхронизируется в Execute }
 procedure DoWork;
 public
 { URL - созданная нами строка, указывающая процессу, какой URL ему нужно скачать }
 URL: string;
 end;
{ В форму нужно поместить три кнопки TButton, одно поле TEdit и один список TListBox. При нажатии на кнопку Button1 вызывается обработчик события OnClick - Button1Click. Перед этим в TEdit нужно ввести путь к каталогу, в котором будут храниться скачанные файлы, а ListBox1 нужно заполнить списком URL-ов для скачивания (с помощью кнопок Add (Button2) и Delete (Button3)). }
procedure TForm1.Button3Click(Sender: TObject);
begin
 { Удаление выделенного URL из списка }
 if ListBox1.ItemIndex >= 0 then
 ListBox1.Items.Delete(ListBox1.ItemIndex);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
 s: string;
begin
 { Добавление URL в список }
 s := InputBox('Добавить','Введите URL:',);
 if s <> then
 ListBox1.Items.Add(s);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
 i: Integer;
begin
 { Проверка на существование каталога }
 if Length(Edit1.Text) > 0 then
 if not DirectoryExists(Edit1.Text) then
 MkDir(Edit1.Text);
 { Далее идет создание для каждого URL в списке своего процесса }
 for i := 0 to ListBox1.Items.Count-1 do
 begin
 with THTTPThread.Create(True) do
 begin
 { Создаем приостановленную задачу, указываем ей ее URL и запускаем ее }
 URL := ListBox1.Items[i];
 Resume;
 end;
 end;
end;
{ Операторы процесса THTTPThread }
procedure THTTPThread.Execute;
begin
 { Делаем так, чтобы каждый процесс выполнялся одновременно с другими (синхронизация) }
 Synchronize(DoWork);
end;
procedure THTTPThread.DoWork;
var
 i: Integer;
begin
 { Создаем компонент TNMHTTP }
 FHTTP := TNMHTTP.Create(Form1);
 { Результат надо записывать в файлы }
 FHTTP.InputFileMode := True;
 { Подбираем имена для файлов }
 i := 1;
 while FileExists(Form1.Edit1.Text + '\page' + IntToStr(i) + '.htm') do
 Inc(i);
 { Указываем, в какие именно файлы класть результат }
 FHTTP.Body := Form1.Edit1.Text + '\body' + IntToStr(i) + '.htm';
 FHTTP.Header := Form1.Edit1.Text + '\header' + IntToStr(i) + '.txt';
 { Пытаемся послать запрос }
 FHTTP.Get(URL);
 { Перед завершением процесса не забываем освободить память из-под компонента }
 FHTTP.Free;
end;
; ПРИМЕЧАНИЕ: Чтобы завершить некоторый процесс (Thread), нужно вызвать метод Terminate класса этого процесса. Приостановить процесс можно оператором Suspend, а продолжить выполнение - Resume. Также можно настроить приоритет каждого отдельного процесса через свойство Priority.
Неплохой пример работы с процессами можно найти в подпапке Demos\Threads папки, куда Вы установили Delphi.
== Замечания по алгоритмам типовых задач ==
Если Вы собираетесь создать скачивалку сайтов, то Вам необходимо учитывать следующее (решить следующие проблемы):
* Нужно скачивать не только саму страничку в формате HTML, но и все входящие в нее рисунки (gif, jpg, и т.д.); 
* в некоторых случаях удобно скачивать не одну страничку, а несколько страниц, ссылки на которые находятся на первой из скачиваемых страничек. При этом нужно учитывать, что на страничке могут находиться и ссылки на другие сайты, поэтому необходимо анализировать скачиваемые ссылки (чтобы случайно не скачать весь Интернет). Для решения задачи со скачиванием нескольких страничек нужно использовать рекурсию; 
* необходимо качественно информировать пользователя о ходе закачки. Т.е. показывать общее и скачанное количество информации; 
* после скачивания нужно заменить Интернетовские ссылки на локальные, чтобы можно было просматривать странички в режиме offline. 
== Эпилог ==
В этой статье отображены основные приемы работы с компонентом TNMHTTP в Дельфи. Если у Вас есть вопросы - скидывайте их мне на E-mail: snick@mailru.com, а еще лучше - пишите в конференции этого сайта (Delphi. Общие вопросы), чтобы и другие пользователи смогли увидеть Ваш вопрос и попытаться на него ответить!
Замечу, что TNMHTTP - не единственный компонент, реализующий доступ по протоколу HTTP. Есть и его аналоги с более расширенными возможностями, например, набор компонентов ICS (Internet Component Suite), в состав которого входит даже компонент FTPServer, позволяющий легко запрограммировать свой собственный сервер FTP для Windows. Этот набор можно скачать на сайте Delphi Super Page.
Author: Карих Николай. Московская область, г.Жуковский
Source: https://www.helloworld.ru/texts/comp/lang/delphi/http/index.htm
ID: 03367
Category:Связь
Category:Статьи
Category:Учебники