【问题标题】:How to download a file over HTTPS using Indy 10 and OpenSSL?如何使用 Indy 10 和 OpenSSL 通过 HTTPS 下载文件?
【发布时间】:2011-01-15 16:48:28
【问题描述】:

我有以下任务:使用 HTTPS 和身份验证下载文件。 Indy 似乎是要走的路,但由于某种原因,它到目前为止还行不通。我有以下内容:

  • 我用来下载的 TIdHTTP 组件
  • 用于创建 URL 的 TIdURI 组件
  • 应该提供安全连接的 TIdSSLIOHandlerSocketOpenSSL 组件。所需的 DLL 位于二进制文件夹中。

该站点还需要身份验证,我在 URL 中包含了用户/密码,如下例所示。简而言之,这是代码:

URI := TIdURI.Create('https://test.example.com/');
URI.Username := ParamUserName;
URI.Password := ParamPassword;

HTTP := TIdHTTP.Create(nil);
if URI.Protocol = 'https' then
begin
  IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  IOHandler.SSLOptions.Method := sslvSSLv3;
  HTTP.IOHandler := IOHandler;
end;

HTTP.Get(URI.GetFullURI([ofAuthInfo]), FileStream);

使用此代码,我很快就会收到“读取超时”EIdReadTimeout 异常。在浏览器中测试 URL 没有问题。关于缺少什么或我做错了什么的任何想法?

【问题讨论】:

  • 应用程序和服务器之间是否有防火墙/代理? “浏览器正常工作”并不意味着有直接的互联网连接。
  • @mjustin 如果我查看浏览器设置,则没有定义代理。此外,WinInet 方法无需设置任何代理即可工作这一事实告诉我,这不是问题。
  • 在这种情况下不要使用 TIdURI.Username/password 属性。您必须改用 TIdHTTP.Username/Password 属性。

标签: delphi openssl indy delphi-2006


【解决方案1】:

我终于放弃了 Indy 和 OpenSSL,使用 WinInet 进行下载。这是对我有用的代码:

function Download(URL, User, Pass, FileName: string): Boolean;
const
  BufferSize = 1024;
var
  hSession, hURL: HInternet;
  Buffer: array[1..BufferSize] of Byte;
  BufferLen: DWORD;
  F: File;
begin
   Result := False;
   hSession := InternetOpen('', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;

   // Establish the secure connection
   InternetConnect (
     hSession,
     PChar(FullURL),
     INTERNET_DEFAULT_HTTPS_PORT,
     PChar(User),
     PChar(Pass),
     INTERNET_SERVICE_HTTP,
     0,
     0
   );

  try
    hURL := InternetOpenURL(hSession, PChar(URL), nil, 0, 0, 0) ;
    try
      AssignFile(f, FileName);
      Rewrite(f,1);
      try
        repeat
          InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen) ;
          BlockWrite(f, Buffer, BufferLen)
        until BufferLen = 0;
      finally
        CloseFile(f) ;
        Result := True;
      end;
    finally
      InternetCloseHandle(hURL)
    end
  finally
    InternetCloseHandle(hSession)
  end;
end;

【讨论】:

  • 关于上面的代码请注意:您应该始终使用 INTERNET_FLAG_RELOAD 参数来强制从服务器而不是缓存下载。所以我建议您将代码更改为:hURL := InternetOpenURL (hSession, PChar(fullURL), nil, 0, INTERNET_FLAG_RELOAD, 0) ;
  • Winapi.WinInet 添加到uses
【解决方案2】:

我也见过同样的事情。将 TIdHTTP.ReadTimeout 设置为零可以解决我的问题。

...
HTTP.IOHandler := IOHandler;
HTTP.ReadTimeout := 0;

【讨论】:

  • ReadTimeout=0 是默认超时值,代表无限超时。
  • 是的,但是在附加 IOHandler 后在代码中设置它似乎可以阻止抛出 EIdReadTimeout 异常。 (至少根据我的经验,使用 Delphi 附带的 Indy 版本)
【解决方案3】:

除非正确安装了一些额外的库,否则所有用于安全连接的 SSL 相关功能都会失败。

1.) Download libraries

2.) 将两个 DLL 解压缩并复制到您的项目文件夹(或系统路径中的某个位置)

您的问题中的代码对我来说很好。

--莱因哈特

【讨论】:

  • 感谢您的回答。我已经准备好 DLL,而且它们似乎已正确加载。读取超时似乎是由其他原因引起的。 WinInet 方法适用于同一台服务器。
猜你喜欢
  • 1970-01-01
  • 2013-04-28
  • 2012-07-16
  • 1970-01-01
  • 2013-09-02
  • 1970-01-01
  • 2012-10-28
  • 2012-12-26
  • 2016-02-02
相关资源
最近更新 更多