【问题标题】:Post a file through https using indy / delphi components使用 indy / delphi 组件通过 https 发布文件
【发布时间】:2013-09-02 13:21:06
【问题描述】:

我正在尝试使用 delphi 中的 Indy 组件通过 https 上传文件。这是我的代码:

HTTP := TIdHTTP.Create(Self)
IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create;   

HTTP.Request.Host           := RemoteHost;
HTTP.Request.Connection     := 'keep-alive';
HTTP.Request.Accept         := 'multipart/mixed';

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


//### CREATE FILE TO SEND           
TestStream := TIdMultipartFormDataStream.Create;
try

  //### POST PARAMETERS
  TestStream.AddFormField('ReceiverId','LOOPTEST');
  TestStream.AddFormField('FileType','LOOPBACK');

  //### ADD FILE        
  TestStream.AddFile('filename','C:\PRUEBA.txt',GetMIMETypeFromFile('C:\PRUEBA.txt'));

  HTTP.Request.ContentType := TestStream.RequestContentType;


  HTTP.Post('https://www.remotehost.com/controller?function=submitfile',TestStream, Resultado);


  memResultado.Lines.Add(Resultado.DataString);


finally
    FreeAndNil(TestStream);
    FreeAndNil(HTTP);
    FreeAndNil(IOHandler);
end;

服务器没有发送任何错误。只是文件没有上传。我的代码有问题吗?

我花了两天时间试图让它工作:S.

任何帮助将不胜感激。我正在使用带有 Indy 版本 10.1.1 的 Delphi XE。

更新:我使用了 Indy TIdLog 组件,结果如下。我找不到任何奇怪的地方:

Stat Connected.
Sent 05/09/2013 12:52:00 p.m.: POST /servlet/controller HTTP/1.1<EOL>Content-Type: application/x-www-form-urlencoded<EOL>Content-Length: 47<EOL>Host: ebmx.extra.client.com<EOL>Accept: text/html, /*<EOL>Accept-Encoding: identity<EOL>User-Agent: Mozilla/3.0 (compatible; Indy Library)<EOL><EOL>
Sent 05/09/2013 12:52:00 p.m.: function=login&username=******&password=******
Recv 05/09/2013 12:52:01 p.m.: HTTP/1.1 200 OK<EOL>Server: Sun-ONE-Web-Server/6.1<EOL>Date: Thu, 05 Sep 2013 17:51:22 GMT<EOL>Content-type: text/html<EOL>Set-cookie: JSESSIONID=8035B4F90EBA1A337E4923520558E5DC;Path=/servlet<EOL>Transfer-encoding: chunked<EOL><EOL>001a<EOL>Success! Member Type is 0<LF><EOL>
Recv 05/09/2013 12:52:01 p.m.: 0<EOL><EOL>
Stat Disconnected.

Stat Connected.
Sent 05/09/2013 12:52:11 p.m.: POST /servlet/controller?function=submitfile HTTP/1.1<EOL>Content-Type: multipart/form-data; boundary=--------090513125207913<EOL>Content-Length: 525<EOL>Host: ebmx.extra.client.com<EOL>Accept: text/html, */*<EOL>Accept-Encoding: identity<EOL>User-Agent: Mozilla/3.0 (compatible; Indy Library)<EOL>Cookie: JSESSIONID=8035B4F90EBA1A337E4923520558E5DC<EOL>Cookie2: $Version="1"<EOL><EOL>
Sent 05/09/2013 12:52:11 p.m.: ----------090513125207913<EOL>Content-Disposition: form-data; name="ReceiverId"<EOL>Content-Type: text/plain<EOL>Content-Transfer-Encoding: quoted-printable<EOL><EOL>LOOPTEST<EOL>----------090513125207913<EOL>Content-Dis‌​position: form-data; name="FileType"<EOL>Content-Type: text/plain<EOL>Content-Transfer-Encoding: quoted-printable<EOL><EOL>LOOPBACK<EOL>----------090513125207913<EOL>Content-Dis‌​position: form-data; name="filename"; filename="PRUEBA.txt"<EOL>Content-Type: text/plain<EOL>Content-Transfer-Encoding: binary<EOL><EOL>UKELELE 2013<EOL>----------090513125207913--<EOL>
Recv 05/09/2013 12:52:15 p.m.: HTTP/1.1 200 OK<EOL>Server: Sun-ONE-Web-Server/6.1<EOL>Date: Thu, 05 Sep 2013 17:51:36 GMT<EOL>Content-type: text/html<EOL>Transfer-encoding: chunked<EOL><EOL>0009<EOL>Failure!<LF><EOL>
Recv 05/09/2013 12:52:16 p.m.: 0<EOL><EOL>  

【问题讨论】:

    标签: delphi https indy


    【解决方案1】:

    HTTP.Request.Host := RemoteHost;

    不要手动设置。 TIdHTTP 将为您管理。

    HTTP.Request.Accept := 'multipart/mixed';

    您告诉服务器您将只接受multipart/mixed 的响应,这是您真正想要的吗?

    HTTP.Request.ContentType := TestStream.RequestContentType;

    发送TIdMultipartFormDataStream 时不要手动设置,Post() 会为您处理。

    HTTP.Post('https://www.remotehost.com/controller?function=submitfile',TestStream, Resultado); memResultado.Lines.Add(Resultado.DataString);

    服务器是否使用与您初始化Resultado 相同的字符集发送响应?如果不是,那么读取DataString 属性可能会失败并返回一个空白字符串(TEncoding 在编码/解码字符串失败时不会引发异常)。您应该让 Indy 为您解码响应数据,因为它知道响应的类型和字符集:

    var
      Resultado: string;
    
    Resultado := HTTP.Post('https://www.remotehost.com/controller?function=submitfile', TestStream);
    memResultado.Lines.Add(Resultado);
    

    服务器没有发送任何错误。只是文件没有上传。

    如果服务器没有发回 HTTP 错误响应(这会导致 TIdHTTP 引发异常),那么它是:

    1. 发回 HTTP 成功响应,但在响应数据中发送错误消息。

    2. 接受文件,但随后丢弃它

    3. 接受文件,但将其保存在与您预期不同的路径/名称下。

    很难确定,因为您没有显示正在传输的实际 HTTP 请求/响应数据。

    更新:服务器IS发回一个错误,使用上面的#1。服务器正在发回一个 HTTP 200 OK 回复,但回复的内容是 'Failure!'(事实上,您的原始代码应该已经在您的 TMemo 中记录了该消息)。这就是TIdHTTP 没有引发异常的原因。它只查找 HTTP 错误,而不是正文内容中的错误消息。您将不得不添加额外的代码来解决这种可能性,例如:

    Resultado := HTTP.Post('https://www.remotehost.com/controller?function=submitfile', TestStream);
    if TextStartsWith(Resultado, 'Failure') then
    begin
      // Upload failed, do something...
    end;
    

    至于为什么服务器首先出现故障,您必须联系服务器管理员并询问。管理员可能会使用服务器端日志进行故障排除。

    但是,我要提到 TIdMultipartFormDataStream 当前确实为文本字段发送了 Content-Type: text/plain 标头,这对于 HTML 4 表单很好(甚至鼓励),但对于 HTML 5 表单则不行(这是被禁止的),如果文本字段存在Content-Type 标头,则某些服务器确实会失败。 HTML5 只允许在文件字段上使用它。这是TIdMultipartFormDataStream 的一个已知问题,已经在处理中,但没有关于何时可用修复的预计时间。但是您可以询问服务器管理员服务器对这种情况的反应。

    【讨论】:

    • 请问这个问题,我怎样才能得到请求/响应数据?。 :S
    • 由于您请求的是 HTTPS 网址,因此不能选择像 Wireshark 这样的数据包嗅探器,因为数据已加密。但是,您可以使用调试代理,如Fiddler,并相应地配置TIdHTTP.ProxyParams 属性。或者,您可以将 Indy 自己的 TIdLog... 组件之一(如 TIdLogFile)附加到 TIdHTTP.Intercept 属性,这样它就可以记录 TIdHTTP 在加密前发送和解密后接收的所有内容。
    • 这种信息需要放到你原来的问题里,不要在cmets里发。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    相关资源
    最近更新 更多