|
Delphi Programming / Object Pascal
[掲載 2008年11月11日] [更新 2017年04月03日] Delphi サンプルプログラム集 |
772_TIdHTTP を使用したダウンロード |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro + Indy 10 (Ver 10.5.7) |
|
772_Indy_HTTPGet.zip [6,378 KB] 2018年11月02日第2版 (EXE 同梱) |
TIdHTTP を使用したダウンロードのサンプルコード |
Delphi に附属している Indy というインターネット関係を操作するためのコンポーネントの TIdHTTP を使用したサンプルです.主に HTTP サーバからファイルをダウンロードするプログラムです. |
URL の文字列を扱う場合,パス名,ファイル名を別々に取出したいことがあります.TIdURL というクラスを使用して,元の URLから下図のような結果を取出すことができます.
TIdHTTP コンポーネントを使用している場合は,URI プロパティから取得できます.URI プロパティの型は TIdURL となっています.
|
|
図1
設計時画面
|
|
図2
実行画面 |
リスト1
UR L文字列をバス等に分解 (HandleRedirects プロパティ使用) |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
LabeledEdit1 : TLabeledEdit;
LabeledEdit2 : TLabeledEdit;
LabeledEdit3 : TLabeledEdit;
LabeledEdit4 : TLabeledEdit;
LabeledEdit5: TLabeledEdit;
LabeledEdit6: TLabeledEdit;
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private 宣言 }
IniFileName : String;
FileSize : Integer;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses IdURI;
{$R *.dfm}
//=============================================================================
// EditにURI(Uniform Resource Identifier)をセット
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
LabeledEdit1.Text := 'http://mrxray.on.coocan.jp/Delphi/plSamples/index.htm';
end;
//=============================================================================
// URL(URI)をプロトコルやホスト文字列に分解する
//
// TIdURIにはusesにIdURIが必要
// IdURIはコンポーネントではなくクラス
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
uri: TIdURI;
begin
//LabelEdit1にURLを入力しておく
uri := TIdURI.Create(LabeledEdit1.Text);
try
LabeledEdit2.Text := uri.Protocol;
LabeledEdit3.Text := uri.Host;
LabeledEdit4.Text := uri.Port;
LabeledEdit5.Text := uri.Path;
LabeledEdit6.Text := uri.Document;
finally
uri.Free;
end;
end;
end.
02_HTTP サーバファイルの情報 ( HandleRedirects プロパティ ) |
HTTP サーバ上のファイルのサイズ,最終更新日等の情報を取得するサンプルです.
HandleRedirects プロパティを True にして,URL のリダイレクトを行います.例えば,CGI 経由でダウンロードするようになっている場合でも,実際のファイル名を取得することができます.リダイレクトの回数はデフォルトで15回となっています. |
|
図3
設計時画面
|
|
図4
実行画面 |
リスト2
HTTP サーバ上のファイルの情報を取得 (HandleRedirects プロパティ使用) |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdHTTP;
type
TForm1 = class(TForm)
Memo1: TMemo;
Panel1: TPanel;
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
IdHTTP1: TIdHTTP;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// テスト用のURLをセット
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
Memo1.Lines.Clear;
Edit1.Text := 'http://mrxray.on.coocan.jp/index.htm';
end;
//=============================================================================
// 指定URLのヘッダ情報を取得
//
// リダイレクト処理を行っているので,例えばCGI経由のファイルも情報取得可能
// (ただし少し時間がかかる)
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
URL : String;
Ret : Boolean;
begin
Memo1.Lines.Clear;
Screen.Cursor := crHourGlass;
URL := Trim(Edit1.Text);
//リダイレクト処理をTrueに
IdHTTP1.HandleRedirects := True;
try
//このURLが存在しないと,Headメソッド実行でエラーとなる
//リダイレクト実行後に,URLにリダイレクト先のURLが取得できる
IdHTTP1.Head(URL);
Ret := True;
except
if IdHTTP1.ResponseCode = 302 then begin
//リダイレクト後のURLで再度Headメソッドを実行して情報取得
IdHTTP1.Head(IdHTTP1.Response.Location);
Ret := True;
end else begin
Ret := False;
end;
end;
if Ret then begin
Memo1.Lines.Add(IdHTTP1.ResponseText);
Memo1.Lines.Add(IdHTTP1.Response.RawHeaders.Text);
Memo1.Lines.Add('');
end else begin
//エラー時の処理
MessageDlg('指定したページまたはファイルが見つかりませんでした.',
mtInformation,
[mbOK],0);
end;
IdHTTP1.Disconnect;
Screen.Cursor := crDefault;
end;
//=============================================================================
// 指定URLの更新日時とファイルサイズを取得
//
// リダイレクト処理を行っているので,例えば
// リダイレクト処理を行っているので,例えばCGI経由のファイルも情報取得可能
// (ただし少し時間がかかる)
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
URL : String;
LastDate : TDateTime;
DateStr : String;
FileSize : Longint;
Ret : Boolean;
begin
Memo1.Lines.Clear;
Screen.Cursor := crHourGlass;
URL := Trim(Edit1.Text);
//リダイレクト処理をTrueに
IdHTTP1.HandleRedirects := True;
try
//このURLが存在しないと,Headメソッド実行でエラーとなる
//リダイレクト実行後に,URLにリダイレクト先のURLが取得できる
IdHTTP1.Head(URL);
Ret := True;
except
if IdHTTP1.ResponseCode = 302 then begin
//リダイレクト後のURLで再度Headメソッドを実行して情報取得
IdHTTP1.Head(IdHTTP1.Response.Location);
Ret := True;
end else begin
Ret := False;
end;
end;
if Ret then begin
//ファイルサイズ
FileSize := IdHTTP1.Response.ContentLength;
//最終更新日時
LastDate := IdHTTP1.Response.LastModified;
DateStr := FormatDateTime('yyyy年mm月dd日 hh時nn分', LastDate);
Memo1.Lines.Add('最終更新日時 : ' + DateStr);
Memo1.Lines.Add('ファイルサイズ : ' + IntToStr(FileSize) + ' バイト' );
Memo1.Lines.Add('フルパス名 : ' + IdHTTP1.URL.URI);
Memo1.Lines.Add('ファイル名 : ' + IdHTTP1.URL.Document);
Memo1.Lines.Add('');
end else begin
//エラー時の処理
MessageDlg('指定したページまたはファイルが見つかりませんでした.',
mtInformation,
[mbOK],0);
end;
IdHTTP1.Disconnect;
Screen.Cursor := crDefault;
end;
end.
03_HTTP サーバファイルの情報 ( Redirect イベント ) |
次のコードもHTTPサーバ上のファイルの情報を取得するサンプルです.こちらは HandleRedirects プロパティではなく,Redirect イベントを使用しています.リダイレクトする度にその値を取得したい場合の参考になります. |
|
図5
設計時画面
|
|
図6
実行画面 |
IdHTTPのResponseText プロパティ (読出し専用) は,以下のいずれかの値です.これらの HTTP サーバから応答で,301, 302 (HTTP1.1 では 307) の場合,多くのブラウザでは自動的にこのコードを認識して,リダイレクト先の URL を読みに行くようになっているようです. |
100 |
Continue
クライアントは処理を続けるべきである
サーバがこのコードをサポートしていな場合は,ヘッダに 100-continue を付加する |
101 |
Switching Protocols
サーバは完全なリクエストを受信したがまだ処理は完了していない
処理に時間がかかる場合に返されるコード |
200 |
OK
リクエストは成功した |
201 |
Created
メソッドによりリソースが生成された場合のコード |
202 |
Accepted
リクエストは受け付けたがリソースの生成は完了していない.リクエストは拒否される可能性がある |
203 |
Non-authoritative Information
200 に同じ.ローカルまたはプロクシからの応答の場合に使用する |
204 |
No Content
リクエストは成功したが,返すべき内容はない
ブラウザ等からのリクエストの場足,レスポンスを受信しても表示は更新されない |
205 |
Reset Content
リクエストは成功した.現在の画面をリセットすべきである |
206 |
Partial Content
サーバはリソースに対する部分的GETリクエストを受け入れた |
301 |
Moved Permanently
指定した URL は移動等によって存在しない.URL の間違い場合等 (最後の / がない等)
Location で示されるリダイレクト先に変更する必要があることもある |
302 |
Moved Temporarily
HTTP1.1 では 307 に変更された
ページが一時的に別の場所に移動した
PHP によるリダイレクトの場合このコードが返される |
303 |
See Other
リクエストに対するレスポンスは別の URL から発見できる |
304 |
Not Modified
クライアントは条件付きGETを実行し,アクセスは許可されたが,更新されていない |
305 |
Use Proxy
リクエストは Location で与えられるプロキシ URL を通してアクセスしなければならない |
307 |
Temporary Redirect
302参照 |
400 |
Bad Request
リクエストの構文が間違っているためサーバは理解できなかった |
401 |
Unauthorized
リクエストはユーザ認証を必要とする
多くのブラウザでは最初は 401 を返さずにユーザ認証入力用のダイアログが現れる |
403 |
Forbidden
サーバはリクエストを理解したが拒否した.認証も役に立たない
サーバは拒否の理由を明らかにする必要はない.代わりに404を返してもよい |
404 |
Not Found
リクエストの URI を見つけられなかった
サーバはその状態が一時的であるか恒久的であるか明らかにする必要 (義務) はない |
405 |
Method Not Allowed
リクエストされた URI にあるリソースは使用されたメソッドを許可していない |
406 |
Not Acceptable
リクエストの Accept ヘッダで指定しなければならない |
407 |
Proxy Authentication Required
クライアントは最初にプロクシのユーザ認証が必要である |
408 |
Request Timeout
サーバの待ち時間にリクエストが終了しなかった
例えばリクエストの終端に CRLF がない場合等 |
409 |
Conflict
リソースが現在の状態と矛盾するためリクエストを完了できなかった
指定ディレクトリが存在しない場合等.WebDAV のレスポンスでみられるコード |
410 |
Gone
リクエストされたリソースはサーバ上に完全にない.サーバが利用できない |
411 |
Length Required
リクエストにContent-Lengthヘッダがない場合 |
412 |
Precondition Failed
リクエストで与えられた条件が適切でない |
413 |
Request Entity To Long
リクエストの処理可能サイズを超えている.この大きさはサーバの設定による |
414 |
Request-URI Too Long. 256 Chars max
リクエストで与えた URI 文字列が長すぎる.このサイズはサーバの設定に依存する |
415 |
Unsupported Media Type
サーバがサポートしていない.サーバに依存する |
500 |
Internal Server Error
サーバ内部のエラー.例えばCGIスクリプトのエラー |
501 |
Not Implemented
サーバはリクエストの機能をサポートしていない
405は機能をサポートしても許可していない場合 |
502 |
Bad Gateway
ゲートウェイであるプロクシが実行アプリケーションから不正なレスポンスを受取った |
503 |
Service Unavailable
サーバの都合により処理できない.メンテナンスか過負荷である場合等 |
504 |
Gateway Timeout
ゲートウェイであるプロクシが実行アプリケーションからレスポンスが受信できなかった |
505 |
HTTP Version not supported
サーバはクライアントの要求した HTTP のバージョンをサポートしていない
Indy はこのエラーを避けるために送信に HTTP1.0 プロトコルを使用している |
リスト3
HTTP サーバ上のファイルの情報を取得 (Redirect イベント使用) |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdHTTP;
type
TForm1 = class(TForm)
Memo1: TMemo;
Panel1: TPanel;
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
IdHTTP1: TIdHTTP;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure IdHTTP1Redirect(Sender: TObject; var dest: string;
var NumRedirect: Integer; var Handled: Boolean; var VMethod: string);
private
{ Private 宣言 }
RealUrl : String;
function CheckHTTPUrl(var AUrl:String): Boolean;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// テスト用のURLをセット
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
Memo1.Lines.Clear;
Edit1.Text := 'http://mrxray.on.coocan.jp/index.htm';
end;
//=============================================================================
// 指定URLのヘッダ情報を取得
//
// リダイレクト処理を行っているので,例えばCGI経由のファイルも情報取得可能
// (ただし少し時間がかかる)
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
URL : String;
begin
Memo1.Lines.Clear;
Screen.Cursor := crHourGlass;
URL :=Trim(Edit1.Text);
if CheckHTTPUrl(URL) = False then begin
MessageDlg('指定したページまたはファイルが見つかりませんでした.',
mtInformation,
[mbOK],0);
Screen.Cursor := crDefault;
exit;
end;
//情報の再取得
//リダイレクトされた場合はURLはりダイレクト先
IdHTTP1.Head(URL);
Memo1.Lines.Add(IdHTTP1.ResponseText);
Memo1.Lines.Add(IdHTTP1.Response.RawHeaders.Text);
IdHTTP1.Disconnect;
Memo1.Lines.Add('');
IdHTTP1.Disconnect;
Screen.Cursor := crDefault;
end;
//=============================================================================
// 指定URLの更新日時とファイルサイズを取得
//
// リダイレクト処理を行っているので,例えばCGI経由のファイルも情報取得可能
// (ただし少し時間がかかる)
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
URL : String;
LastDate : TDateTime;
DateStr : String;
FileSize : Longint;
begin
Memo1.Lines.Clear;
Screen.Cursor := crHourGlass;
URL := Trim(Edit1.Text);
if CheckHTTPUrl(URL) = False then begin
MessageDlg('指定したページまたはファイルが見つかりませんでした.',
mtInformation,
[mbOK],0);
Screen.Cursor := crDefault;
exit;
end;
//情報の再取得
//リダイレクトされた場合はURLはりダイレクト先
IdHTTP1.Head(URL);
FileSize := IdHTTP1.Response.ContentLength;
LastDate := IdHTTP1.Response.LastModified;
//最終更新日時
DateStr :=FormatDateTime('yyyy年mm月dd日 hh時nn分', LastDate);
Memo1.Lines.Add('最終更新日時 : ' + DateStr);
Memo1.Lines.Add('ファイルサイズ : ' + IntToStr(FileSize) + ' バイト' );
Memo1.Lines.Add('フルパス名 : ' + IdHTTP1.URL.URI);
Memo1.Lines.Add('ファイル名 : ' + IdHTTP1.URL.Document);
Memo1.Lines.Add('');
IdHTTP1.Disconnect;
Screen.Cursor := crDefault;
end;
//=============================================================================
// 引数のAUrlが存在するかチェックする関数
// RealUrlはグローバル変数.OnRedirectイベントとの連携で取得する
// 成功すればAUrlにリダイレクト先(なければ元のAUrlはそのまま)を返す
//=============================================================================
function TForm1.CheckHTTPUrl(var AUrl: String): Boolean;
begin
RealUrl := Aurl;
try
IdHTTP1.Head(RealUrl);
AUrl := RealUrl;
Result := True;
except
AUrl := '';
Result := False;
end;
//リダイレクトされている場合はエラーとしない
if IdHTTP1.ResponseCode = 302 then begin
AUrl := RealUrl;
Result := True;
end;
Memo1.Lines.Add(RealUrl);
end;
//=============================================================================
// IdHTTPのOnRedirect(リダイレクト)イベント
// グローバル変数のRealUrlにリダイレクト先のアドレスを取得してIdHTTPのコマンド
// の再実行を行うようにしている
// リダイレクトの回数は,RedirectMaxmum(デフォルトでは15)で設定する
//
// [参考]
// リダイレクト(サーバからの応答)のステータスコード
// 301 Moved Permanently -- ページの引越しで完全にない
// 302 Moved Temporarily(HTTP1.1では307に変更?) -- 別の場所にある
// HTTP/1.1 404 Not Found.の場合はリダイレクトを中止する
//=============================================================================
procedure TForm1.IdHTTP1Redirect(Sender: TObject; var dest: string;
var NumRedirect: Integer; var Handled: Boolean; var VMethod: string);
begin
if Pos('404.htm', dest) > 0 then begin
Handled := False;
RealUrl := '';
end else begin
RealUrl := dest;
Handled := True;
end;
end;
end.
HTTP サーバ上の指定ファイルを,GET メソッドでダウンロードするサンプルです.
ダウンロードするファイルがテキストファイルの場合は,文字のコードページに注意します.適切なコードページに変換しないと,ダウンロードしたテキストが文字化けが発生します. |
|
図7
設計時画面
|
|
図8
ダウンロード中 |
リスト4
HTTP サーバ上のファイルをダウンロード |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdHTTP, StdCtrls, ExtCtrls, ComCtrls;
type
TForm1 = class(TForm)
IdHTTP1: TIdHTTP;
Button1: TButton;
Memo1: TMemo;
Panel2: TPanel;
Panel3: TPanel;
LabeledEdit1: TLabeledEdit;
ProgressBar1: TProgressBar;
SaveDialog1: TSaveDialog;
Panel1: TPanel;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus;
const AStatusText: String);
procedure IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
AWorkCount: Int64);
procedure IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
AWorkCountMax: Int64);
private
{ Private 宣言 }
AStream : TFileStream;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses HTTPApp;
{$R *.dfm}
//=============================================================================
// ダウンロードファイル名をLabelEditに入力
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
Memo1.Clear;
LabeledEdit1.Text := 'http://mrxray.on.coocan.jp/Delphi/ZipExe/plSetPrinter.zip';
end;
//=============================================================================
// IdHTTPでダウンロードする
//
// リダイレクト処理を行っているので,例えばCGI経由のファイルも情報取得可能
// (ただし少し時間がかかる)
// htm,html等の場合はソーステキストの取得となるので画像類はタウンロードしない
//
// SourceFile : ダウンロードするファイル名
// SaveFile : ダウンロード後のファイル名
// TSaveDialogで変更可能
//
// UnixPathToDosPath関数にはusesにHTTPAppが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
SourceFile : String;
SaveFile : String;
Ret : Boolean;
begin
Memo1.Lines.Clear;
Panel1.Caption := '';
SourceFile := LabeledEdit1.Text;
ProgressBar1.Position := 0;
Screen.Cursor := crHourGlass;
//リダイレクト処理をTrueに
IdHTTP1.HandleRedirects := True;
//ファイルまたはページが見つかったら保存先を選択してダウンロード
try
//このURLが存在しないと,Headメソッド実行でエラーとなる
//リダイレクト実行後に,URLにリダイレクト先のURLが取得できる
IdHTTP1.Head(SourceFile);
Ret := True;
except
if IdHTTP1.ResponseCode = 302 then begin
//リダイレクト後のURLで再度Headメソッドを実行して情報取得
IdHTTP1.Head(IdHTTP1.Response.Location);
Ret := True;
end else begin
Ret := False;
end;
end;
if Ret then begin
SourceFile := IdHTTP1.URL.URI;
SaveFile := ExtractFilePath(ParamStr(0)) +
ExtractFileName(UnixPathToDosPath(SourceFile));
SaveDialog1.FileName := SaveFile;
if SaveDialog1.Execute then begin
Update;
AStream := TFileStream.Create(SaveDialog1.FileName, fmCreate);
try
IdHTTP1.Get(SourceFile, AStream);
finally
FreeAndNil(AStream);
end;
Panel1.Caption := 'ダウンロード終了';
end;
end else begin
MessageDlg('指定したページまたはファイルが見つかりませんでした.',
mtInformation,
[mbOK],0);
end;
IdHTTP1.Disconnect;
Screen.Cursor := crDefault;
end;
//=============================================================================
// IdHTTPのOnWorkBeginイベント
// プログレスバーの最大値をセット
//=============================================================================
procedure TForm1.IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
AWorkCountMax: Int64);
begin
ProgressBar1.Max := AWorkCountMax;
end;
//=============================================================================
// IdHTTPのOnWorkイベント
// ダウンロードの進捗(進行)状況をプログレスバーに表示
//=============================================================================
procedure TForm1.IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
AWorkCount: Int64);
var
StrText : String;
begin
ProgressBar1.Position := AWorkCount;
StrText := IntToStr(AStream.Size - AStream.Position);
Panel1.Caption :='残り ' + StrText + ' バイト';
Panel1.Update;
end;
//=============================================================================
// IdHTTPのOnStatusイベント
// 接続やダウンロードの状態をMemoに表示
//=============================================================================
procedure TForm1.IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus;
const AStatusText: String);
begin
Memo1.Lines.Add(AStatusText);
end;
end.
05_HTTP サーバからファイルをダウンロード ( スレッドを 使用 ) |
HTTP サーバからファイルをダウンロードします.IdHTTP コンポーネントの GET メソッドは,ストリームにまとめてダウンロードするため,通常は途中でのキャンセルはできません.
TIdThreadComponent コンポーネントを使用すると,キャンセルの機能を持たせることができます.本サンプルではこのコンポーネントを使用して,[キャンセル] ボタンをクリックしたら,ダウンロードを中止するようにしてみました. |
|
図9
設計時画面
|
|
図10
実行画面 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdHTTP, StdCtrls, ExtCtrls, ComCtrls, IdThreadComponent;
type
TForm1 = class(TForm)
IdHTTP1: TIdHTTP;
Panel2: TPanel;
ProgressBar1: TProgressBar;
SaveDialog1: TSaveDialog;
Button1: TButton;
Button2: TButton;
LabeledEdit1: TLabeledEdit;
Panel1: TPanel;
IdThreadComponent1: TIdThreadComponent;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode;
AWorkCount: Int64);
procedure IdHTTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode;
AWorkCountMax: Int64);
procedure IdThreadComponent1Run(Sender: TIdThreadComponent);
private
{ Private 宣言 }
FSaveFileName : String;
FSourceFile : String;
FSourceFileSize : Int64;
FIsCancel : Boolean;
FDownLoadError : Boolean;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses HTTPApp, IdThread;
{$R *.dfm}
//=============================================================================
// ダウンロードファイル名をLabelEditに入力
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
LabeledEdit1.Text := 'http://mrxray.on.coocan.jp/Delphi/ZipExe/plSetPrinter.zip';
end;
//=============================================================================
// フォームを閉じる時の処理
// 接続中の時は接続を切断してスレッドを終了する
//=============================================================================
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if IdHTTP1.Connected then begin
IdThreadComponent1.Stop;
IdHTTP1.Disconnect;
FIsCancel := True;
end;
end;
//=============================================================================
// IdHTTPでダウンロードする
// リダイレクト処理を行っているので,例えばCGI経由のファイルも情報取得可能
// (ただし少し時間がかかる)
// htm,html等の場合はソーステキストの取得となるので画像類はタウンロードしない
//
// UnixPathToDosPath関数にはusesにHTTPAppが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LIsSrcFile : Boolean;
begin
FSourceFile := LabeledEdit1.Text;
ProgressBar1.Position := 0;
//リダイレクト処理をTrueに
IdHTTP1.HandleRedirects := True;
try
//このURLが存在しないとHeadメソッド実行でエラーとなる
//リダイレクト実行後に,URLにリダイレクト先のURLが取得できる
IdHTTP1.Head(FSourceFile);
LIsSrcFile := True;
except
if IdHTTP1.ResponseCode = 302 then begin
//リダイレクト後のURLで再度Headメソッドを実行して情報取得
IdHTTP1.Head(IdHTTP1.Response.Location);
LIsSrcFile := True;
end else begin
LIsSrcFile := False;
end;
end;
//ダウンロードするファイルが存在する場合
if LIsSrcFile then begin
FSourceFile := IdHTTP1.URL.URI;
FSaveFileName := ExtractFilePath(Application.ExeName) +
ExtractFileName(UnixPathToDosPath(FSourceFile));
FSourceFileSize := IdHTTP1.Response.ContentLength;
SaveDialog1.FileName := FSaveFileName;
//ローカルの保存先設定
if SaveDialog1.Execute then begin
FSaveFileName := SaveDialog1.FileName;
Screen.Cursor := crHourGlass;
FDownLoadError := False;
//スレッドを開始してダウンロード開始
IdThreadComponent1.Start;
//ダウンロードが終了するまで(スレッドが終了するで)待つ
//OnTerminateやOnStoppedイベントで処理する方法も考えられる
while True do begin
if IdThreadComponent1.Terminated then Break;
Application.ProcessMessages;
Sleep(1);
end;
if FIsCancel then begin
MessageDlg('ダウンロードを中止しました', mtInformation, [mbOK],0);
end else
//ダウンロードに失敗した場合
if FDownLoadError then begin
MessageDlg('ダウンロードに失敗しました', mtInformation,[mbOK],0);
end else begin
Panel1.Caption := 'ダウンロード終了';
end;
end;
end else begin
MessageDlg('指定したページまたはファイルが見つかりませんでした',
mtInformation,
[mbOK],0);
end;
IdHTTP1.Disconnect;
Screen.Cursor := crDefault;
end;
//=============================================================================
// キャンセルボタン
// ダウンロード途中のファイルが存在するので,削除した方がいいかも知れない
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
if IdHTTP1.Connected then begin
FIsCancel := True;
IdHTTP1.Disconnect;
IdThreadComponent1.Stop;
end;
end;
//=============================================================================
// IdThreadComponent1のOnRunイベント
// このイベント内でダウンロード処理を行う
//=============================================================================
procedure TForm1.IdThreadComponent1Run(Sender: TIdThreadComponent);
var
LStream : TFileStream;
begin
LStream := TFileStream.Create(FSaveFileName, fmCreate);
try
try
//FSourceFileをダウンロードしてLStreamに格納
IdHTTP1.Get(FSourceFile, LStream);
except
//ダウンロード失敗
FDownLoadError := True;
end;
finally
IdThreadComponent1.Terminate;
if IdHTTP1.Connected then begin
IdHTTP1.Disconnect;
end;
FreeAndNil(LStream);
end;
end;
//=============================================================================
// IdHTTP1のOnWorkBeginイベント処理
// ダウンロードを開始すると発生するイベント
//=============================================================================
procedure TForm1.IdHTTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode;
AWorkCountMax: Int64);
begin
ProgressBar1.Max := FSourceFileSize;
end;
//=============================================================================
// IdHTTP1のOnWorkイベント処理
// ダウンロード中に発生するイベント
//=============================================================================
procedure TForm1.IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode;
AWorkCount: Int64);
var
LStrText : String;
begin
ProgressBar1.Position := AWorkCount;
LStrText := IntToStr(FSourceFileSize - AWorkCount);
Form1.Panel1.Caption :='残り ' + LStrText + ' バイト';
end;
end.
Indy のバージョンは,Indy の各コンポーネントの Version プロパティで知ることができます. |
|
図11
設計時画面
|
|
図12
実行画面 |
リスト6
インストールされている Indy のバージョンを知る方法 |
unit IndyVersionUnit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdHTTP;
type
TForm1 = class(TForm)
Button1: TButton;
IdHTTP1: TIdHTTP;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// Indyのバージョンを調べる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
Application.MessageBox(PChar(IdHTTP1.Version), 'バージョン番号');
end;
end.
TIdHTTP を使用して,HTTPS サーバにアクセス (SSL 通信) 手順が下記の記事にあります.
本項の記事とサンプルは,これらの記事を元に作成しています. |
OpenSSL の libeay32.dll と ssleay32.dll が必要です.これらの DLL は,Delphi のインストール先の [bin] フォルダ内にありますが,以下のページからも SSL 通信制御関係のファイルとしてダウンロードできます.
|
今回のテストでは,32 ビットの EXE で使用するので,以下のファイルをダウンロードしました.i386 は 32 ビットの DLL が添付されているファイルです.64 ビットの EXE で使用する場合は,x64 という 64 ビット版の DLL が含まれているファイルをダウンロードします.
|
openssl-0.9.8r-i386-win32-rev2.zip 2017-04-02 04:08 831K |
ダウンロードしたファイルに含まれている libeay32.dll と ssleay32.dll という 2 つの DLL をプログラムの実行ファイルがあるフォルダにコピーします.Delphi のヘルプには,システム関係フォルダに置くように書いてありますが,システム関係のフォルダ等には置かないようにします.SSL 通信を必要するアプリケーションでは,これらと同名の DLL が使われていて,それらも,そのアプリケーション固有のフォルダ内に置いてあります.
必要であれば openssl.exe もアプリケーションの実行ファイルのフォルダに置きます.openssl.exe は OpenSSL のコマンドラインツールです.
次に,フォームに Indy の TIdSSLIOHandlerSocketOpenSSL コンポーネントを配置します.
そして,TIdHTTP コンポの IOHandler プロパティの値を,この TIdSSLIOHandlerSocketOpenSSL とします.
接続に失敗する場合は, より新しいバージョンの DLL をダウンロードして使用したり,以下の備考のリンクの記事にあるように,TIdSSLIOHandlerSocketOpenSSL コンポーネントの SSLOptins.Method の値を変更してみてください.
|
[備考 1]
ダウンロードすべき DLL の説明が間違っていたのを 2017年04月03日に修正しました.
2017年04月03日現在の最新のバージョンの DLL が使用可能なのは Indy 10.5.5 以上です.
|
[備考 2]
FTP での SSL の機能は,Indy 8, Indy 9 では利用できません. |
[備考 3]
SSL (Secure Sockets Layer) は,インターネットでデータを暗号化して送受信するための通信手順の一種です.TLS (Transport Layer Security) は SSL の新しい基準ですが,SSL という名前が広く普及しているため SSL/TLS 等と表記することがあります. |
[備考 4]
GitHub 等,意味がある User Agent の情報が送られてこないとアクセスを拒否するウェブサイトあるいはウェブページがあります.
|
|
図13
IOHandler プロパティの設定
|
|
図14
SSLOptins.Method の設定
- 接続に失敗した場合は sslvSSLv23 にすると接続できることがある
- デフォルトは sslvTLSv1
|
以下が実際の実行結果とテストに使用したコードです.
テストに使用しているウェブページは,ファイル名が取得できません.そこで,リダイレクト等の処理は省略しています.タイムアウトの時間も設定していません.保存ファイル名を決め打ちにしています.必要に応じて変更してください.
|
|
図15
設計時画面
- TIdSSLIOHandlerSocketOpenSSL を配置
|
|
図16
実行結果
|
リスト7
HTTPS サーバからファイルをダウンロードする簡単な例
ここでは,ウェブページの HTML ファイルをダウンロード |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdHTTP, StdCtrls, ExtCtrls, ComCtrls, IdIOHandler, IdIOHandlerSocket,
IdIOHandlerStack, IdSSL, IdSSLOpenSSL;
type
TForm1 = class(TForm)
IdHTTP1: TIdHTTP;
Button1: TButton;
Memo1: TMemo;
Panel3: TPanel;
LabeledEdit1: TLabeledEdit;
Panel1: TPanel;
IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus;
const AStatusText: String);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
LabeledEdit1.Text := 'https://code.google.com/p/indydocs/';
end;
//=============================================================================
// IdHTTPでダウンロードする
//
// SourceFile : ダウンロードするファイル名
// SaveFile : ダウンロードしたファイルの保存ファイル名
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LSourceFile : String;
LSaveFile : String;
LStream : TFileStream;
begin
Memo1.Lines.Clear;
Panel1.Caption := '';
LSourceFile := LabeledEdit1.Text;
Screen.Cursor := crHourGlass;
//リダイレクト処理をTrueに
IdHTTP1.HandleRedirects := True;
LSaveFile := ExtractFilePath(ParamStr(0)) + 'AAA.html';
LStream := TFileStream.Create(LSaveFile, fmCreate);
try
IdHTTP1.Get(LSourceFile, LStream);
finally
FreeAndNil(LStream);
end;
Panel1.Caption := 'ダウンロード終了';
IdHTTP1.Disconnect;
Screen.Cursor := crDefault;
end;
//=============================================================================
// IdHTTP1のOnStatusイベント
// 接続等の状態をTMemoに表示
//=============================================================================
procedure TForm1.IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus;
const AStatusText: String);
begin
Memo1.Lines.Add(AStatusText);
end;
end.
08_THttpClient または TNetHttpClient を使用する接続処理 |
Delphi XE8 以降の Delphi
であれば,HTTP サーバ,あるいは HTTPS サーバの接続やデータの取得,送信等の操作に THttpClient あるいは TNetHttpClient を使用すると便利です.
Indy は 前項のサンプルのように SSL の機能を独自で処理しますが,THttpClient, TNetHttpClient
は OS に実装されている SSL 通信の機能を使用して処理します.
THttpClient のインスタンスは実行時に生成して使用します.TNetHttpClient はコンポーネントパレットの [Net] タブにあります.
|
|