我正在尝试在Delphi XE6和Indy(v10.6.2.0)中进行HTTPS Post请求。
我已成功使用JavaScript调用此API并获取响应:
但我需要在Delphi应用程序中进行相同的操作。
我尝试了多次使用TIdSSLIOHandlerSocketOpenSSL
的不同配置,但出现错误:
无法加载SSL库
libeay32.dll
是罪魁祸首。我也去了Indy的GitHub仓库,但不确定需要下载哪个依赖文件。
下面的代码给我带来了错误:
无法打开文件“C:\Users..\IndyHTTPSTest\Win32\Debug\dXNlcm5hbWU6cGFzc3dvcmQ =”。系统找不到指定的文件。
我需要怎样才能像JavaScript代码一样在Delphi XE6中运行它?
我已经在我的项目文件夹中包含了libeay32.dll
和ssleay32.dll
。以下是我的代码:
unit uMainForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent, IdSSLOpenSSL, IdSSLOpenSSLHeaders,
System.NetEncoding, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP;
type
TMainForm = class(TForm)
IdHTTP1: TIdHTTP;
GetBtn: TButton;
ResponseMemo: TMemo;
procedure GetBtnClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
ss: TStringStream;
s, sLog, sFile : String;
Base64: TBase64Encoding;
Txt: TextFile;
implementation
{$R *.dfm}
procedure TMainForm.FormCreate(Sender: TObject);
begin
// Assign JSON to TStringStream
ss := TStringStream.Create('locations= [{"address":"Test1","lat":"52.05429","lng":"4.248618"},{"address":"Test2","lat":"52.076892","lng":"4.26975"},{"address":"Test3","lat":"51.669946","lng":"5.61852"},{"address":"Sint-Oedenrode, The Netherlands","lat":"51.589548","lng":"5.432482"}]', TEncoding.UTF8);
// Base64 encode username and password string to satisfy API for "Authorization", "Basic " + sLog);
s := 'username:password';
Base64 := TBase64Encoding.Create(20, '');
sLog := Base64.Encode(s);
end;
procedure TMainForm.GetBtnClick(Sender: TObject);
var
responseFromServer, sWhichFail, sVer :string;
LHandler: TIdSSLIOHandlerSocketOpenSSL;
begin
LHandler := TIdSSLIOHandlerSocketOpenSSL.Create(self);
with LHandler do
begin
SSLOptions.Method := sslvSSLv2;
SSLOptions.Mode := sslmUnassigned;
SSLOptions.VerifyMode := [];
SSLOptions.VerifyDepth := 0;
host := '';
end;
IdHTTP1 := TIdHTTP.Create(Self);
with IdHTTP1 do
begin
IOHandler := LHandler;
AllowCookies := True;
ProxyParams.BasicAuthentication := False;
ProxyParams.ProxyPort := 0;
Request.ContentLength := -1;
Request.ContentType := 'application/x-www-form-urlencoded';
Request.ContentRangeEnd := 0;
Request.ContentRangeStart := 0;
Request.Accept := 'text/json, */*';
Request.BasicAuthentication := True;
Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
HTTPOptions := [hoForceEncodeParams];
end;
try
// Set up the request and send it
sFile:= IdHTTP1.Post('https://api.routexl.com/tour', sLog);
ResponseMemo.Lines.Add(Format('Response Code: %d', [IdHTTP1.ResponseCode]));
ResponseMemo.Lines.Add(Format('Response Text: %s', [IdHTTP1.ResponseText]));
finally
sWhichFail:= WhichFailedToLoad();
ShowMessage(sWhichFail);
ResponseMemo.Lines.Text:= sWhichFail;
//sVer := OpenSSLVersion();
//ShowMessage(sVer);
end;
end;
end.
更新:我已经更新了代码,并添加了屏幕截图来帮助调试:unit uMainForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent, IdSSLOpenSSL, IdSSLOpenSSLHeaders,
System.NetEncoding, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP;
type
TMainForm = class(TForm)
IdHTTP1: TIdHTTP;
GetBtn: TButton;
ResponseMemo: TMemo;
procedure GetBtnClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
sl: TStringList;
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.FormCreate(Sender: TObject);
begin
sl := TStringList.Create;
sl.Add('locations=[{"address":"Test1","lat":"52.05429","lng":"4.248618"},{"address":"Test2","lat":"52.076892","lng":"4.26975"},{"address":"Test3","lat":"51.669946","lng":"5.61852"},{"address":"Sint-Oedenrode, The Netherlands","lat":"51.589548","lng":"5.432482"}]');
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
sl.Free;
end;
procedure TMainForm.GetBtnClick(Sender: TObject);
var
LHTTP: TIdHTTP;
LHandler: TIdSSLIOHandlerSocketOpenSSL;
responseFromServer, sWhichFail, sVer :string;
begin
ResponseMemo.Clear;
LHTTP := TIdHTTP.Create(nil);
try
LHandler := TIdSSLIOHandlerSocketOpenSSL.Create(LHTTP);
LHandler.SSLOptions.SSLVersions := [sslvTLSv1_2];
LHandler.SSLOptions.Mode := sslmClient;
LHandler.SSLOptions.VerifyMode := [];
LHandler.SSLOptions.VerifyDepth := 0;
LHTTP.IOHandler := LHandler;
LHTTP.AllowCookies := True;
LHTTP.Request.Accept := 'text/json, */*';
LHTTP.Request.BasicAuthentication := True;
LHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
LHTTP.Request.Username := 'username:';
LHTTP.Request.Password := 'password';
LHTTP.HTTPOptions := [hoForceEncodeParams];
try
responseFromServer := IdHTTP1.Post('https://api.routexl.com/tour', sl);
ResponseMemo.Lines.Text := responseFromServer;
except
on E: EIdOSSLCouldNotLoadSSLLibrary do
begin
sVer := OpenSSLVersion();
sWhichFail := WhichFailedToLoad();
ResponseMemo.Lines.Add(sVer);
ResponseMemo.Lines.Add(sWhichFail);
ShowMessage('Could not load OpenSSL');
end;
on E: EIdHTTPProtocolException do
begin
ResponseMemo.Lines.Add(Format('Response Code: %d', [LHTTP.ResponseCode]));
ResponseMemo.Lines.Add(Format('Response Text: %s', [LHTTP.ResponseText]));
ResponseMemo.Lines.Add(E.ErrorMessage);
ShowMessage('HTTP Failure');
end;
on E: Exception do
begin
ResponseMemo.Lines.Add(E.ClassName);
ResponseMemo.Lines.Add(E.Message);
ShowMessage('Unknown Error');
end;
end;
finally
LHTTP.Free;
end;
end;
end.
执行JavaScript代码时,WireShark显示以下内容:
当执行 Delphi 代码时,WireShark 显示以下内容:
Post()
的第二个参数是文件名。 - Olivier