【问题标题】:Weird indy redirect post奇怪的印地重定向帖子
【发布时间】:2017-08-31 20:31:34
【问题描述】:

我正在尝试使用 Indy 发送发布请求,但我遇到了一些问题。 在一个表单中,我有 TIdHTTP、一个 TIdSSLIOHandlerSocketOpenSSL 和一个 TIdCookieManager,它们具有以下属性:

TIdHTTP:

IdHTTP1.IOHandler := FSSLIO;
IdHTTP1.AllowCookies := True;
IdHTTP1.HandleRedirects := True;
IdHTTP1.ProxyParams.BasicAuthentication := False;
IdHTTP1.ProxyParams.ProxyPort := 0;
IdHTTP1.Request.ContentLength := -1;
IdHTTP1.Request.Accept := 'text/html, */*';
IdHTTP1.Request.BasicAuthentication := False;
IdHTTP1.Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
IdHTTP1.HTTPOptions := [hoKeepOrigProtocol, hoForceEncodeParams];
IdHTTP1.OnRedirect := IdHTTP1Redirect;
IdHTTP1.CookieManager := IdCookieManager1;        

TIdSSLIOHandlerSocketOpenSSL:默认值

TIdCookieManager: 默认值

OnRedirect 过程:

Handled := True;

在一个按钮中请求如下:

Params := TStringStream.Create('asdf=asdf',TEncoding.UTF8);    
edtmemo1.Text := IdHTTP1.Post('https://www.detran.mg.gov.br/habilitacao/1-habilitacao-quero-ser-condutor/consultar-resultado-exame-legislacao/-/busca_resultado_exames/', Params);
Params.Free;

但返回错误,响应代码为 301,但奇怪的是该位置与我尝试发送的 url 相同,因此它进入了无限循环。

回应

HTTP/1.1 301 Moved Permanently
Date: Thu, 31 Aug 2017 20:23:32 GMT
Server: Apache
X-Powered-By: PHP/5.3.5
P3P: CP="A politica de privacidade deve estar disponivel no site ou pode ser solicitada via fale conosco."
Set-Cookie: SECCCAKEPHP=e19ttp30m5380ih41qal0gipg2; expires=Sat, 09-Sep-2017 04:23:32 GMT; path=/
Location: https://www.detran.mg.gov.br/habilitacao/1-habilitacao-quero-ser-condutor/consultar-resultado-exame-legislacao/-/busca_resultado_exames/
Cache-Control: max-age=604800
Expires: Thu, 07 Sep 2017 20:23:32 GMT
Content-Length: 0
Content-Type: text/html; charset=utf-8

卷曲测试:

curl -vv -X POST -F 'asdf=asdf' https://www.detran.mg.gov.br/habilitacao/1-habilitacao-quero-ser-condutor/consultar-resultado-exame-legislacao/-/busca_resultado_exames/

我使用 curl 尝试了相同的请求并使用响应代码 200。 知道会发生什么吗?

【问题讨论】:

  • 服务器正在重定向到相同的 URL,但它也发送了一个可能在初始请求中丢失的 cookie。如果服务器想要返回该 cookie,这是合理的行为。如果服务器陷入无休止的重定向循环,那就是另一个问题了。嗅探流量以查看 curl 发送的内容与 TIdHTTP 发送的内容。要嗅探 curl 的 HTTPS 流量,您可以使用Fiddler。要嗅探TIdHTTP 的HTTPS 流量,您可以将TIdLog... 组件(例如TIdLogFile)分配给TIdHTTP.Intercept 属性。 TIdHTTP 会发回那个 cookie 吗?
  • 你传递给 curl 的命令行参数是什么?什么Params 传递给TIdHTTP.Post()?请提供minimal reproducible example 显示您实际为重现该问题所做的一切。此外,Delphi 2010 已有 8 年历史,您是否使用同样旧版本的 Indy?在撰写本文时,当前的 Indy 版本是 10.6.2.5434。
  • 我编辑了问题,添加了 curl 请求,并且使用这些参数 curl 不处理重定向,而是使用 200 代码响应。我可以在 curl 中模拟相同问题的唯一方法是,如果我使用 http 而不是 https。是的,我知道 Delphi 2010 已经过时了,是的,我使用的是 Indy 10.5.5 版,我们已经尝试过更新,至少是 Indy,但是我们遇到了很多问题,不幸的是我们没有足够的时间或人员来处理用它。
  • 您的 TIdHTTP 逻辑与您的 curl 逻辑不匹配。我发布了一个解释差异的答案。

标签: delphi post delphi-2010 indy


【解决方案1】:

如果您阅读curl documentation,您会看到-F 选项以multipart/form-data 格式发布数据:

-F, --form

(HTTP) 这让 curl 模拟用户按下提交按钮的填写表单。 这会导致 curl 根据RFC 2388 使用 Content-Type multipart/form-data 发布数据。这可以上传二进制文件等。

但是,您的 TIdHTTP 代码正在发布 application/x-www-form-urlencoded 格式的数据。更重要的是,您没有将 TIdHTTP.Request.ContentType 属性设置为 'application/x-www-form-urlencoded' 以匹配数据。如果您发布TStream,则必须相应地设置ContentType

TIdHTTP 更喜欢使用TStrings 派生对象(如TStringList)而不是TStream 发布application/x-www-form-urlencoded 数据,因此它可以确保数据被正确编码和格式化,例如:

var
  Params: TStringList;
begin
  ...
  Params := TStringList.Create;
  try
    Params.Add('asdf=asdf'); // <-- DO NOT url-encode the values here!
    // the TStrings version of Post() will set the Request.ContentType
    // to 'application/x-www-form-urlencoded' by default...
    edtmemo1.Text := IdHTTP1.Post('https://www.detran.mg.gov.br/habilitacao/1-habilitacao-quero-ser-condutor/consultar-resultado-exame-legislacao/-/busca_resultado_exames/', Params);
  finally
    Params.Free;
  end;
  ...
end;

TIdHTTP 更喜欢使用 TIdMultipartFormDataStream 对象来发布 multipart/form-data 数据(除非您传递另一个包含预先格式化的 MIME 数据的 TStream)。

所以,要匹配你的 curl 命令发送的内容,试试这个:

uses
  ..., IdMultipartFormData;

var
  Params: TIdMultipartFormDataStream;
begin
  ...
  Params := TIdMultipartFormDataStream.Create;
  try
    Params.AddFormField('asdf', 'asdf', 'utf-8');
    // the TIdMultipartFormDataStream version of Post() will set the
    // Request.ContentType to 'multipart/form-data' with a suitable
    // MIME 'boundary' attribute for you...
    edtmemo1.Text := IdHTTP1.Post('https://www.detran.mg.gov.br/habilitacao/1-habilitacao-quero-ser-condutor/consultar-resultado-exame-legislacao/-/busca_resultado_exames/', Params);
  finally
    Params.Free;
  end;
  ...
end;

【讨论】:

  • 非常感谢@remy-lebeau 的回答,尝试了您的建议,但不幸的是没有奏效。现在它使用Content-Type: multipart/form-data; boundary=--------090117161550011 发送。但结果相同
  • 使用当前版本的 Indy 和您在问题中显示的确切代码,我无法重现该问题。在不进行我在回答中建议的任何更改的情况下,服务器会回复 200 包含 HTML 文档,而不是回复 301 重定向。因此,您需要执行我最初建议的操作:“嗅探流量以查看 curl 发送的内容与 TIdHTTP 发送的内容”。很明显,您机器上的 TIdHTTP 请求中有(或缺少)服务器不喜欢的东西。 curl 发送的任何内容,TIdHTTP 都可以使用正确的编码进行复制
  • 我尝试使用Fiddler,我认为这可能是SSL的一些问题,因为在fiddler尝试CONNECT到服务器,并返回408错误请求。
  • CONNECT 是通过 HTTP 代理建立 HTTPS 连接的传统方式,CONNECT 不会被发送到目标服务器。配置为连接到 HTTP 代理(例如使用 curl 的 -x 选项)的 HTTPS 客户端(如 curl)将连接到 Fiddler(代理)并请求它到 CONNECT 到目标服务器的 TCP 连接。一旦建立 TCP 连接,客户端将直接与目标服务器协商 SSL/TLS 会话,然后将其 HTTP 请求直接发送到目标服务器。服务器不会知道涉及到代理。
  • Fiddler is able to debug HTTPS。当客户端尝试与目标服务器协商 SSL/TLS 会话时,Fiddler 拦截请求并通过向客户端发送自己的 SSL/TLS 回复来伪装成目标服务器(因此,如果客户端必须接受 Fiddler 的证书,进行证书验证,否则协商失败并关闭连接),然后 Fiddler 冒充客户端与目标服务器协商 SSL/TLS 会话,然后在两个会话之间传递数据。
猜你喜欢
  • 2013-09-17
  • 1970-01-01
  • 2018-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-20
  • 2011-08-05
相关资源
最近更新 更多