使用Indy TIdHTTP遇到问题怎么办

9

我在使用Indy的TIdHTTP向亚马逊的SES服务发布内容时遇到了问题。

以下是我使用的示例代码:

procedure TMainFrm.btnAmazonSESClick(Sender: TObject);
var
  SSLHandler: TIdSSLIOHandlerSocket;
  HttpClient: TIdHTTP;  
  Params: TStringStream;
begin
  SSLHandler := TIdSSLIOHandlerSocket.Create(Self);
  HttpClient := TIdHTTP.Create(Self);  
  Params := TStringStream.create('');
  try
    with SSLHandler do
      SSLOptions.Method := sslvSSLv3
    with HttpClient do
    begin
      IOHandler := SSLHandler;
      AllowCookies := True;
      HandleRedirects := True;
      HTTPOptions := [hoForceEncodeParams];
      Request.ContentType := 'application/x-www-form-urlencoded';
    end;

    PageMemo.Text := HttpClient.Post('https://email.us-east-1.amazonaws.com?Action=VerifyEmailAddress&AWSAccessKeyId=012Some123Key46&EmailAddress=test@test%2Ecom', Params);

  finally
    SSLHandler.Free;
    HttpClient.Free; 
    Params.Free;
  end;
end;

结果

  • 在Indy 10.5.7下,我收到了错误:HTTP/1.1 404 Not Found。

  • 在Indy 9.0.14下,我收到了错误:Socket Error # 11004。

调试尝试

  • 相同的演示可以成功获取HTTPS网页的HTML。

  • 如果我将上面的URL粘贴到浏览器中,它会显示预期的XML结果。

我希望能得到有关原因的任何建议。


2
我认为您需要将SSL dll文件放在应用程序的同一文件夹或Windows system32文件夹中...如果您想让我在某个地方上传我拥有的文件,请告诉我,我的版本是libeay32.dll 1.0.0.4和ssleay32.dll 1.0.0.4。 - user497849
1
您没有POST任何Params,您确定要以这种方式与Web服务进行通信吗? - Premature Optimization
1
@PrematureOptimization 在此之后的所有内容都是参数名=值,例如在本例中,Action=VerifyEmailAddress&AWSAccessKeyId=012Some123Key46&EmailAddress=test@test%2Ecom。 - user497849
1
@Dorin Duminica,不是很对。查询字符串<>表单数据。 - Premature Optimization
@DorinDuminica:谢谢,我已经将最新的SSL DLL文件包含在文件夹中。 - Zax
2个回答

3
这篇文章只是一个不完整的猜测,也许Remy可以帮助您纠正错误。通过以下代码,我得到了HTTP/1.1 400 Bad Request的错误信息,但这并不奇怪,因为API参考中提到了关于常见查询参数的内容,其中至少需要创建请求的数字签名,而这正是我不知道如何做的。
我无法进行任何测试,因为我在那里没有账户。但我认为

procedure TForm1.Button1Click(Sender: TObject);
var
  HTTPClient: TIdHTTP;
  Parameters: TStrings;
  SSLHandler: TIdSSLIOHandlerSocketOpenSSL;

begin
  SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  HTTPClient := TIdHTTP.Create(nil);
  Parameters := TStringList.Create;

  try
    SSLHandler.SSLOptions.Method := sslvSSLv3;
    SSLHandler.SSLOptions.Mode := sslmUnassigned;

    HTTPClient.IOHandler := SSLHandler;
    HTTPClient.HTTPOptions := [hoForceEncodeParams];
    HTTPClient.Request.ContentType := 'application/x-www-form-urlencoded';

    Parameters.Add('Action=VerifyEmailAddress');
    Parameters.Add('EmailAddress=test@test.com');
    Parameters.Add('AWSAccessKeyId=012Some123Key46');
    Parameters.Add('SignatureVersion=2');
    Parameters.Add('Expires='); // ???
    Parameters.Add('Signature='); // ???

    PageMemo.Text := HTTPClient.Post('https://email.us-east-1.amazonaws.com', Parameters);

  finally
    SSLHandler.Free;
    HTTPClient.Free; 
    Parameters.Free;
  end;
end;

谢谢,我会尝试,但我不明白为什么在Indy和将相同的URL粘贴到浏览器中会得到不同的结果。换句话说,如果问题是由于参数引起的,那么我应该收到他们的XML失败结果!? - Zax
例如,Firefox即使收到“HTTP 400 Bad Request”错误,也会显示内容。例如,Internet Explorer会告诉您发生了错误请求,并且不会显示XML内容响应,Indy也是如此,它会创建错误消息并丢弃内容。您示例中的请求具有错误的参数,即IncompleteSignature,根据表格所述,这将导致HTTP状态代码= 400(错误请求)。 - TLama
感谢您填补我理解上的空白。现在我正在取得良好的进展。 - Zax
@TLama:如果发生HTTP错误,TIdHTTP不会丢弃响应内容。相反,它将其作为引发的EIdHTTPProtocolException异常的属性公开。 - Remy Lebeau
“我不明白为什么在Indy和将相同的URL粘贴到浏览器中会得到不同的结果” - 如果您将 https://email.us-east-1.amazonaws.com?Action=VerifyEmailAddress&AWSAccessKeyId=012Some123Key46&EmailAddress=test@test%2Ecom 粘贴到浏览器中,它会发送一个GET请求而不是POST请求,因此在Indy中做同样的操作,例如:PageMemo.Text := HttpClient.Get('https://email.us-east-1.amazonaws.com?Action=VerifyEmailAddress&AWSAccessKeyId=012Some123Key46&EmailAddress=test@test%2Ecom');。否则,将name=value pair放入TStringList中并进行Post()。” - Remy Lebeau
必须使用数字签名来创建请求,但我不知道如何操作” - 这在亚马逊的文档中有详细解释:签名版本4签名流程 - Remy Lebeau

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接