TIdHTTPProxyServer 引发 "Unknown Protocol" RSHTTPUnknownProtocol 异常
TIdHTTPProxyServer raising "Unknown Protocol" RSHTTPUnknownProtocol exception
我正在使用 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;
为了测试,我在主机文件中添加了 127.0.0.1 localtest123.com 和 127.0.0.1 www.localtest123.com 并禁用了 DNS 缓存服务。然后在多个浏览器中我请求 http://localtest123.com/ and http://www.localtest123.com/。使用 OutputDebugString() 我可以看到已接受连接,但随后引发 "Unknown Protocol" 错误。
我在 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 不需要太多代码就可以工作,所以我不得不寻求有关此异常的帮助。提前致谢!
您不能只重定向 HOSTS
文件中的域并期望事情神奇地起作用。这不是代理的工作方式。
您必须明确配置 Web 浏览器以通过 HTTP 代理发出 HTTP 请求,以便它们格式化代理可以理解的正确请求。将 HTTP 请求直接发送到目标 Web 服务器的处理方式不同于通过代理发送相同的 HTTP 请求。
您收到异常是因为浏览器请求未正确定位您的代理。
例如,当浏览器直接向目标 Web 服务器发送 HTTP GET
请求时,它会直接连接到该服务器,然后发送如下所示的请求:
GET /path HTTP/1.1
Host: server.com
但是,当它通过 HTTP 代理发送相同的请求时,它会连接到代理并发送看起来更像这样的请求:
GET http://server.com/path HTTP/1.1
您的浏览器请求中缺少 GET
行中的额外路径信息,因为您没有将浏览器配置为代理,因此当 TIdHTTPProxyServer
试图确定信息时出现异常它需要连接到目标 Web 服务器并将当前请求转发给它。
这是 HTTP 工作原理的根本,也是 TIdHTTPProxyServer
设计工作原理的基础。
当涉及到 HTTPS 时,事情会稍微复杂一些,但我暂时不考虑这个细节,因为它与您关于异常的问题无关。
更新:在评论中,您说:
In the XE version it never raised an exception when checking for the protocol which would still work today because I manually set the host and port in DoHTTPBeforeCommand.
在那个旧版本中,没有引发异常,因为TIdHTTPProxyServer
还没有检查协议来区分 HTTP 和 HTTPS。当收到不是专门针对您的代理的请求时,您可以手动填写缺失的信息。这就是为什么事情以前对你有用。
在更高版本中,TIdHTTPProxyServer
已更新以在请求中未明确指定端口时区分 HTTP 和 HTTPS,因此默认端口是根据请求的协议设置的。该检查发生在 DoHTTPBeforeCommand()
被调用之前。
要恢复旧行为,您必须更改 TIdHTTPProxyServer
的源代码以将异常的引发延迟到 DoHTTPBeforeCommand()
returns 之后,因此您有一个有机会再次填写缺失值。
如果您 file a feature request 这样做,我可能会考虑将其添加到 Indy 的官方代码中。
我正在使用 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;
为了测试,我在主机文件中添加了 127.0.0.1 localtest123.com 和 127.0.0.1 www.localtest123.com 并禁用了 DNS 缓存服务。然后在多个浏览器中我请求 http://localtest123.com/ and http://www.localtest123.com/。使用 OutputDebugString() 我可以看到已接受连接,但随后引发 "Unknown Protocol" 错误。
我在 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 不需要太多代码就可以工作,所以我不得不寻求有关此异常的帮助。提前致谢!
您不能只重定向 HOSTS
文件中的域并期望事情神奇地起作用。这不是代理的工作方式。
您必须明确配置 Web 浏览器以通过 HTTP 代理发出 HTTP 请求,以便它们格式化代理可以理解的正确请求。将 HTTP 请求直接发送到目标 Web 服务器的处理方式不同于通过代理发送相同的 HTTP 请求。
您收到异常是因为浏览器请求未正确定位您的代理。
例如,当浏览器直接向目标 Web 服务器发送 HTTP GET
请求时,它会直接连接到该服务器,然后发送如下所示的请求:
GET /path HTTP/1.1
Host: server.com
但是,当它通过 HTTP 代理发送相同的请求时,它会连接到代理并发送看起来更像这样的请求:
GET http://server.com/path HTTP/1.1
您的浏览器请求中缺少 GET
行中的额外路径信息,因为您没有将浏览器配置为代理,因此当 TIdHTTPProxyServer
试图确定信息时出现异常它需要连接到目标 Web 服务器并将当前请求转发给它。
这是 HTTP 工作原理的根本,也是 TIdHTTPProxyServer
设计工作原理的基础。
当涉及到 HTTPS 时,事情会稍微复杂一些,但我暂时不考虑这个细节,因为它与您关于异常的问题无关。
更新:在评论中,您说:
In the XE version it never raised an exception when checking for the protocol which would still work today because I manually set the host and port in DoHTTPBeforeCommand.
在那个旧版本中,没有引发异常,因为TIdHTTPProxyServer
还没有检查协议来区分 HTTP 和 HTTPS。当收到不是专门针对您的代理的请求时,您可以手动填写缺失的信息。这就是为什么事情以前对你有用。
在更高版本中,TIdHTTPProxyServer
已更新以在请求中未明确指定端口时区分 HTTP 和 HTTPS,因此默认端口是根据请求的协议设置的。该检查发生在 DoHTTPBeforeCommand()
被调用之前。
要恢复旧行为,您必须更改 TIdHTTPProxyServer
的源代码以将异常的引发延迟到 DoHTTPBeforeCommand()
returns 之后,因此您有一个有机会再次填写缺失值。
如果您 file a feature request 这样做,我可能会考虑将其添加到 Indy 的官方代码中。