我正在尝试在 Indy 中编写一个代理服务器来接收来自外部客户端的 HTTPS 调用,并将它们以 HTTP 形式转发到同一台机器上的另一个服务器应用程序。原因是其他应用程序不支持 SSL,因此我想将其流量包装在 SSL 层中以实现外部安全。
我目前的方法是使用带有 SSL IOHandler 的 TIdHTTPserver,在它的 OnCommandGet 处理程序中,我动态创建了一个 TIdHTTP 客户端,它从内部应用程序获取 TFileStream ContentStream,并将该流作为 Response.ContentStream 返回到外部来电者。
这种方法的问题是在开始发送外部流之前必须等待内部内容流被完全接收而导致的延迟。例如,它不适用于流媒体。
我的问题是:是否有更好的方法将 HTTPS 代理到适用于流的 HTTP?即无需使用中间文件流。
最佳答案
如果发出请求的客户端支持 HTTP 1.1 分块(请参阅 RFC 2616 Section 3.6.1 ),这将允许您从目标服务器读取数据并立即将其实时发送到客户端。
如果您使用的是较新版本的 Indy,TIdHTTP
有一个 OnChunkReceived
事件,以及一个 hoNoReadChunked
在其 HTTPOptions
中标记属性:
New TIdHTTP flags and OnChunkReceived event
在你的TIdHTTPServer.OnCommand...
事件处理程序,您可以填充 AResponseInfo
如所须。确保:
离开
AResponseInfo.ContentText
和AResponseInfo.ContentStream
未分配设置
AResponseInfo.ContentLength
到 0设置
AResponseInfo.TransferEncoding
至'chunked'
然后调用AResponseInfo.WriteHeader()
直接方法,例如 TIdHTTP.OnHeadersRecceived
事件,将响应 header 发送到客户端。
然后您可以使用OnChunkedReceived
读取目标服务器的响应正文或 hoNoReadChunked
,并使用 AContext.Connection.IOHandler
将每个接收到的 block 写入客户端直接。
但是,有一些注意事项:
如果您使用
TIdHTTP.OnChunkReceived
事件,您仍然需要提供输出TStream
至TIdHTTP
否则事件不会被触发(在未来的版本中可能会删除此限制)。但是,您可以使用TIdEventStream
没有分配OnWrite
它的事件处理程序。或者写一个自定义TStream
覆盖虚拟的类Write()
什么都不做的方法。或者,只使用任何TStream
你想要,并拥有OnChunkReceived
事件处理程序清除收到的Chunk
所以没有什么可以写入TStream
.如果您使用
hoNoReadChunked
标志,这允许您手动从TIdHTTP.IOHandler
读取 HTTP block 直接在TIdHTTP
之后导出。只要确保启用 HTTP keep-alives 否则TIdHTTP
将在您有机会读取服务器的响应正文之前关闭与服务器的连接。
如果您使用的是旧版本的 Indy,或者如果目标服务器不支持分块,则不会丢失所有内容。您应该能够编写自定义 TStream
覆盖虚拟的类 Write()
方法将提供的数据 block 作为 HTTP block 写入客户端。然后你可以使用那个类作为输出 TStream
对于 TIdHTTP
.
如果客户端不支持 HTTP 分块,或者如果这些方法对您不起作用,那么您可能不得不求助于使用 TIdTCPServer
直接代替 TIdHTTPServer
并从头开始自己实现整个 HTTP 协议(protocol),然后您可以根据需要处理自己的流媒体。查看 TIdHTTPProxyServer
的源代码对于一些想法(TIdHTTPProxyServer
本身并不适合您的特定情况,但它会告诉您如何在一般情况下近乎实时地在连接之间传递 HTTP 请求/响应)。
关于http - Indy 代理服务器 HTTPS 到 HTTP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41504247/