【问题标题】:Error downloading protocol with https : // - Delphi使用 https 下载协议时出错:// - Delphi
【发布时间】:2015-08-12 21:40:30
【问题描述】:

我想知道如何在 Delphi 中使用协议 https:// 下载文件。我正在使用 idhttp ,但是当我点击下载时它返回错误代码:

-1

点击按钮后,几秒钟后它会终止应用程序。

uses: IdHTTP, IdSSLOpenSSL;

IdHTTP1 := TIdHTTP.create(nil);
 try
            IdHTTP1.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);  
            IdHTTP1.Request.Accept := 'text/html, */*';
            IdHTTP1.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
            IdHTTP1.Request.ContentType := 'application/x-www-form-urlencoded';
            IdHTTP1.HandleRedirects := True;
            IdHTTP1.get(FNomeArq,MS);
            Ms.Seek(0,soFromBeginning);
            header := IdHTTP1.Response.ContentType;
 except on E : EIdHTTPProtocolException do begin
             showmessage(intToStr(IdHTTP1.ResponseCode));
            end;
            on E: EIdSocketError do begin
                showmessage(intToStr(IdHTTP1.ResponseCode));
            end;
            on E: Exception do begin
              showmessage(intToStr(IdHTTP1.ResponseCode));
            end;
 end;

【问题讨论】:

  • 引发了什么异常类?什么是错误信息。如果您只是停止尝试处理异常,您可能会得到一些有用的信息。
  • 什么平台?您的可执行文件所在的目录中是否有 OpenSSL 库文件?
  • 这是在您抑制错误时发生的情况。请不要那样做。你已经竭尽全力让自己的生活变得艰难。你应该学会避免处理异常。
  • 如果这是针对 iOS 的,请参见此处:community.embarcadero.com/index.php/blogs/entry/…

标签: delphi delphi-xe5


【解决方案1】:

首先,您的错误处理是错误的。您只显示 TIdHTTP.ResponseCode 属性值,没有其他内容。 ResponseCode 具有有意义值的唯一例外是EIdHTTPProtocolException(即使这样,您也应该从EIdHTTPProtocolException.ErrorCode 属性中获取值)。 ResponseCode 不太可能填充任何其他异常,这显然是您的情况。由于您会遇到捕获不同类型异常的麻烦,因此您应该显示对这些特定类型有意义的错误消息,例如:

except
  on E: EIdHTTPProtocolException do begin
    ShowMessage('HTTP request failed'#13 + IntToStr(E.ErrorCode) + ' ' + E.Message);
  end;
  on E: EIdOpenSSLAPISSLError do
  begin
    ShowMessage('OpenSSL API failure'#13 + E.ClassName + #13'Result Code: ' + IntToStr(E.RetCode) + #13'Error Code: ' + IntToStr(E.ErrorCode));
  end;
  on E: EIdOpenSSLAPICryptoError do
  begin
    ShowMessage('OpenSSL crypto failure'#13 + E.ClassName + #13'Error Code: ' + IntToStr(E.ErrorCode));
  end;
  on E: EIdOpenSSLError do
  begin
    ShowMessage('Unknown OpenSSL error'#13 + E.ClassName + #13 + E.Message);
  end;
  on E: EIdSocketError do begin
    ShowMessage('Socket error'#13 + E.ClassName + #13'Error Code: ' + IntToStr(E.LastError) + ' ' + E.Message);
  end;
  on E: Exception do begin
    ShowMessage('Unexpected error'#13 + E.ClassName + #13 + E.Message);
  end;
end;

其次,如果您在桌面系统(Windows 或 OSX)上运行您的应用程序,您将泄漏您的 TIdSSLIOHandlerSocketOpenSSL 对象,因为您没有为它分配 Owner,并且 TIdHTTP 没有获得所有权其中。如果您在移动系统(iOS 或 Android)上运行您的应用程序,您的代码将崩溃,因为在创建 TIdSSLIOHandlerSocketOpenSSL 对象后没有任何引用来保持其活动状态。 TIdTCPConnection.IOHandlerTIdTCPConnection.Socket 属性在这些平台上使用 weak 引用,因此对象的引用计数不会增加,最终会被提前销毁。如果您不分配 Owner,则需要显式释放该对象,例如在 try/finally 中,就像 Zam 的回答所展示的那样。

或者,如果您使用的是最新版本的 Indy,您可以利用今年早些时候添加到 TIdHTTP 的新 HTTPS 功能,因此您不必创建 IOHandler明确对象:

New HTTPS functionality for TIdHTTP

第三,关于你得到的实际异常,EIdOSSLCouldNotLoadSSLLibrary 的意思正是它的名字所暗示的。无法加载 OpenSSL 库。这意味着要么找不到 DLL(libeay32.dll 和 ssleay32.dll),要么没有导出 Indy 查找的所有内容。您可以调用IdSSLOpenSSLHeaders单元中的WhichFailedToLoad()函数来查找OpenSSL无法加载的原因:

except
  //...
  on E: EIdOSSLCouldNotLoadSSLLibrary do
  begin
    ShowMessage('Could not load OpenSSL library'#13'Failed to load: ' + WhichFailedToLoad);
  end;
  //...
end;

确保您已安装兼容版本的 OpenSSL DLL,无论是在应用程序的文件夹中、操作系统搜索路径上的文件夹中,还是在您通过 @987654343 中的 IdOpenSSLSetLibPath() 函数指定给 Indy 的文件夹中@ 单元。通常,您应该努力始终使用可用的最新 OpenSSL 版本(在撰写本文时为 1.0.2d)。

【讨论】:

    【解决方案2】:

    首先,您没有使用所有必需的单位。

    uses
        IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL;
    

    这是工作示例,在 Delphi XE7 和 XE8 下测试。 FMX 平台。

    var
        FResponse: TMemoryStream;
    
    procedure Load;
    var
        LUrl: String;
        IdHTTP: TIdHTTP;
        IdSSLIOHandlerSocketOpenSSL: TIdSSLIOHandlerSocketOpenSSL;
    begin
        LUrl := 'https://google.lv/';
    
        IdHTTP := TIdHTTP.Create(nil);
        try
          IdSSLIOHandlerSocketOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
          try
            IdHTTP.IOHandler := IdSSLIOHandlerSocketOpenSSL;
            try
              IdHTTP.Get(LUrl, FResponse);
            except
              { We are hiding error }
            end;
          finally
            IdSSLIOHandlerSocketOpenSSL.Free;
          end;
        finally
          IdHTTP.Free;
        end;
    end;
    

    不要忘记使用FResponse := TMemoryStream.Create;创建FResponse

    最后:确保您使用的是正确的 OpenSSL 库 对于我正在使用的 Indy 10.6.1.5182:

    [WIN][x86] OpenSSL 共享库 1.0.1.7; OpenSSL 工具包 1.0.1g;

    libeay32.dll
    1 281 024 bytes
    
    ssleay32.dll
    270 336 bytes
    

    [WIN][x64] OpenSSL 共享库 1.0.1.7; OpenSSL 工具包 1.0.1g;

    libeay32.dll
    1 817 088 bytes
    
    ssleay32.dll
    371 200 bytes
    

    【讨论】:

      猜你喜欢
      • 2021-01-21
      • 1970-01-01
      • 1970-01-01
      • 2014-06-27
      • 2010-09-13
      • 1970-01-01
      • 2014-01-24
      • 2019-11-26
      • 1970-01-01
      相关资源
      最近更新 更多