idhttp - 加载页面时获取响应字符串
idhttp - get response string while loading page
我需要在加载页面之前获取接收到的字符串(与 asterix http AMI 事件一起使用)。
所以我试图在 idHttp 的 OnWork 事件中访问接收到的字符串,但出现错误:
var
Form2: TForm2;
s:TStringStream;
procedure TForm2.Button1Click(Sender: TObject);
begin
s:=TStringStream.Create;
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10',s);
showmessage(s.DataString); //NO ERROR
end;
procedure TForm2.IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode;
AWorkCount: Int64);
begin
showmessage(s.DataString); //ERROR HERE
end;
更新:
我按照 Remy Lebeau 的建议创建了自定义 class (TAMIStringStream),但仍然出现错误。我做错了什么?
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdHTTP, cxGraphics, cxControls, cxLookAndFeels,
cxLookAndFeelPainters, cxContainer, cxEdit, Vcl.StdCtrls, cxTextEdit, cxMemo,
cxCheckBox;
type
TAMIStringStream = class(TStringStream)
FEncoding: TEncoding;
public
ReceivedSTR:string;
function Write(const Buffer; Count: Longint): Longint; override;
end;
TForm2 = class(TForm)
IdHTTP1: TIdHTTP;
Button1: TButton;
cxCheckBox1: TcxCheckBox;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
s:TAMIStringStream;
implementation
{$R *.dfm}
function TAMIStringStream.Write(const Buffer; Count: Longint): Longint;
var t:string;
begin
Inherited;
t := FEncoding.GetString(Bytes, Position - Count, Count);
form2.memo1.lines.add(t);
ReceivedSTR := ReceivedSTR + t;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=login&username=1cami&secret=111');
s:=TAMIStringStream.Create;
while cxCheckBox1.Checked do begin
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10',s);
end;
end;
end.
要在 TIdHTTP
下载服务器的 HTTP 响应数据时获取它,您需要编写自己的 TStream
派生 class 来覆盖虚拟 TStream.Write()
方法,然后您可以将 class 的实例传递给 TIdHTTP.Get()
的 AResponseContent
参数。您的 Write()
方法可以在数据流 "written" 时处理数据(准备好以任意块的形式处理该数据,因为它是实时流式传输)。
否则,您将不得不完全跳过 TIdHTTP
并使用 TIdTCPClient
,手动实现 HTTP 协议,以便您完全控制读写。
"AMI over HTTP" 协议文档(参见 this and this)显示了如何向 AMI 发送 HTTP 请求以及如何轮询事件(是的,使用 HTTP 时必须轮询事件)。由于在传递事件之前轮询不会return,因此没有太多理由在运行中读取服务器的响应数据。 TIdHTTP.Get()
会阻塞直到收到事件,然后你可以根据需要进行处理。因此,如果没有自定义流,您的第一种方法应该没问题:
procedure TForm2.Button1Click(Sender: TObject);
var
s: TStringStream;
begin
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=login&username=1cami&secret=111');
s := TStringStream.Create;
try
while cxCheckBox1.Checked do
begin
IdHttp1.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10', s);
Memo1.Lines.Add(s.DataString);
s.Clear;
end;
finally
s.Free;
end;
end;
或者:
procedure TForm2.Button1Click(Sender: TObject);
var
s: String;
begin
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=login&username=1cami&secret=111');
while cxCheckBox1.Checked do
begin
s := IdHttp1.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10');
Memo1.Lines.Add(s);
end;
end;
由于 TIdHTTP
的阻塞性质,我建议将轮询移动到工作线程中:
procedure TMyThread.Execute;
var
http: TIdHTTP;
s: String;
begin
http := TIdHTTP.Create(nil);
try
http.Get('http://website.com:8088/asterisk/rawman?action=login&username=1cami&secret=111');
while not Terminated do
begin
s := http.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10');
// do something...
end;
finally
http.Free;
end;
end;
如果 HTTP 轮询不适合您的需要,您应该考虑使用 "AMI over TCP"(参见 this and this),并为此使用 TIdTCPClient
。您可以使用计时器或线程来检查传入数据。
我需要在加载页面之前获取接收到的字符串(与 asterix http AMI 事件一起使用)。 所以我试图在 idHttp 的 OnWork 事件中访问接收到的字符串,但出现错误:
var
Form2: TForm2;
s:TStringStream;
procedure TForm2.Button1Click(Sender: TObject);
begin
s:=TStringStream.Create;
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10',s);
showmessage(s.DataString); //NO ERROR
end;
procedure TForm2.IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode;
AWorkCount: Int64);
begin
showmessage(s.DataString); //ERROR HERE
end;
更新: 我按照 Remy Lebeau 的建议创建了自定义 class (TAMIStringStream),但仍然出现错误。我做错了什么?
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdHTTP, cxGraphics, cxControls, cxLookAndFeels,
cxLookAndFeelPainters, cxContainer, cxEdit, Vcl.StdCtrls, cxTextEdit, cxMemo,
cxCheckBox;
type
TAMIStringStream = class(TStringStream)
FEncoding: TEncoding;
public
ReceivedSTR:string;
function Write(const Buffer; Count: Longint): Longint; override;
end;
TForm2 = class(TForm)
IdHTTP1: TIdHTTP;
Button1: TButton;
cxCheckBox1: TcxCheckBox;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
s:TAMIStringStream;
implementation
{$R *.dfm}
function TAMIStringStream.Write(const Buffer; Count: Longint): Longint;
var t:string;
begin
Inherited;
t := FEncoding.GetString(Bytes, Position - Count, Count);
form2.memo1.lines.add(t);
ReceivedSTR := ReceivedSTR + t;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=login&username=1cami&secret=111');
s:=TAMIStringStream.Create;
while cxCheckBox1.Checked do begin
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10',s);
end;
end;
end.
要在 TIdHTTP
下载服务器的 HTTP 响应数据时获取它,您需要编写自己的 TStream
派生 class 来覆盖虚拟 TStream.Write()
方法,然后您可以将 class 的实例传递给 TIdHTTP.Get()
的 AResponseContent
参数。您的 Write()
方法可以在数据流 "written" 时处理数据(准备好以任意块的形式处理该数据,因为它是实时流式传输)。
否则,您将不得不完全跳过 TIdHTTP
并使用 TIdTCPClient
,手动实现 HTTP 协议,以便您完全控制读写。
"AMI over HTTP" 协议文档(参见 this and this)显示了如何向 AMI 发送 HTTP 请求以及如何轮询事件(是的,使用 HTTP 时必须轮询事件)。由于在传递事件之前轮询不会return,因此没有太多理由在运行中读取服务器的响应数据。 TIdHTTP.Get()
会阻塞直到收到事件,然后你可以根据需要进行处理。因此,如果没有自定义流,您的第一种方法应该没问题:
procedure TForm2.Button1Click(Sender: TObject);
var
s: TStringStream;
begin
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=login&username=1cami&secret=111');
s := TStringStream.Create;
try
while cxCheckBox1.Checked do
begin
IdHttp1.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10', s);
Memo1.Lines.Add(s.DataString);
s.Clear;
end;
finally
s.Free;
end;
end;
或者:
procedure TForm2.Button1Click(Sender: TObject);
var
s: String;
begin
idhttp1.Get('http://website.com:8088/asterisk/rawman?action=login&username=1cami&secret=111');
while cxCheckBox1.Checked do
begin
s := IdHttp1.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10');
Memo1.Lines.Add(s);
end;
end;
由于 TIdHTTP
的阻塞性质,我建议将轮询移动到工作线程中:
procedure TMyThread.Execute;
var
http: TIdHTTP;
s: String;
begin
http := TIdHTTP.Create(nil);
try
http.Get('http://website.com:8088/asterisk/rawman?action=login&username=1cami&secret=111');
while not Terminated do
begin
s := http.Get('http://website.com:8088/asterisk/rawman?action=waitevent&timeout=10');
// do something...
end;
finally
http.Free;
end;
end;
如果 HTTP 轮询不适合您的需要,您应该考虑使用 "AMI over TCP"(参见 this and this),并为此使用 TIdTCPClient
。您可以使用计时器或线程来检查传入数据。