3

我正在使用 Delphi 10.3 Rio 重新编码一个旧的 Delphi XE 程序。它使用 TIdHTTPProxyServer Indy 组件监听 127.0.0.1:80。

  with IdHTTPProxyServer.Bindings.Add do begin

    IP := '127.0.0.1';
    Port := 80;

  end;

  IdHTTPProxyServer.Active := True;

为了测试,我在 hosts 文件中添加了 127.0.0.1 localtest123.com 和 127.0.0.1 www.localtest123.com 并禁用了 DNS 缓存服务。然后在多个浏览器中我请求http://localtest123.com/http://www.localtest123.com/。使用 OutputDebugString() 我可以看到连接被接受,但随后引发“未知协议”错误。

我在 IdHTTPProxyServer.pas 中的 TIdHTTPProxyServer.CommandPassThrough 过程中调试了异常。似乎 LURI.Protocol 是一个空字符串,这就是引发 RSHTTPUnknownProtocol 的原因。

  LContext := TIdHTTPProxyServerContext(ASender.Context);
  LContext.FCommand := ASender.CommandHandler.Command; //<-'GET'
  LContext.FTarget := ASender.Params.Strings[0]; //<-'/'

  LContext.FOutboundClient := TIdTCPClient.Create(nil);
  try
    LURI := TIdURI.Create(LContext.Target); //<-'/'
    try
      TIdTCPClient(LContext.FOutboundClient).Host := LURI.Host; //<-''

      if LURI.Port <> '' then begin //<-''
        TIdTCPClient(LContext.FOutboundClient).Port := IndyStrToInt(LURI.Port, 80);
      end
      else if TextIsSame(LURI.Protocol, 'http') then begin //<-''    {do not localize}
        TIdTCPClient(LContext.FOutboundClient).Port := IdPORT_HTTP;
      end
      else if TextIsSame(LURI.Protocol, 'https') then begin //<-'' {do not localize}
        TIdTCPClient(LContext.FOutboundClient).Port := IdPORT_https;
      end else begin
        raise EIdException.Create(RSHTTPUnknownProtocol);
      end;

我可能遗漏了一些东西,但 TIdHTTPProxyServer 无需太多代码就可以工作,所以我不得不就这个异常寻求帮助。提前致谢!

4

1 回答 1

1

您不能只重定向HOSTS文件中的域并期望事情神奇地起作用。这不是代理的工作方式。

您必须明确配置 Web 浏览器以通过 HTTP 代理发出 HTTP 请求,以便它们格式化代理可以理解的正确请求。将 HTTP 请求直接发送到目标 Web 服务器的处理方式与通过代理发送相同的 HTTP 请求不同。

您收到异常是因为浏览器请求未正确定位您的代理。

例如,当浏览器GET直接向目标 Web 服务器发送 HTTP 请求时,它会直接连接到该服务器,然后发送如下所示的请求:

GET /path HTTP/1.1
Host: server.com

但是,当它通过 HTTP 代理发送相同的请求时,它会连接到代理并发送一个看起来更像这样的请求:

GET http://server.com/path HTTP/1.1

您的浏览器请求中缺少该GET行中的额外路径信息,因为您没有为代理配置浏览器,因此在TIdHTTPProxyServer尝试确定与目标 Web 服务器建立连接并转发当前向它提出要求。

这从根本上是关于 HTTP 是如何工作的,以及TIdHTTPProxyServer设计是如何工作的。

当涉及 HTTPS 时,事情会稍微复杂一些,但我暂时不考虑这个细节,因为它与您关于异常的问题无关。

更新:在评论中,你说:

在 XE 版本中,它在检查今天仍然有效的协议时从未引发异常,因为我在 DoHTTPBeforeCommand 中手动设置了主机和端口。

在那个旧版本中,没有出现异常,因为TIdHTTPProxyServer还没有检查协议来区分 HTTP 和 HTTPS。当收到并非专门针对您的代理的请求时,您可以手动填写缺失的信息。这就是为什么以前对你有用的原因。

在以后的版本中,TIdHTTPProxyServer当请求中没有明确指定端口时,已更新以区分 HTTP 和 HTTPS,因此根据请求的协议设置默认端口。该检查发生在DoHTTPBeforeCommand()调用之前。

要恢复旧行为,您必须更改TIdHTTPProxyServer源代码以延迟引发异常直到DoHTTPBeforeCommand()返回之后,这样您就有机会再次填写缺失值。

如果您为此提出功能请求,我可能会考虑将其添加到 Indy 的官方代码中。

于 2019-05-27T04:08:56.140 回答