我正在使用Swift为iOS/tvOS使用TLS创建一个Http/2代理。我的代理初创公司:
var tlsConfiguration = ...
tlsConfiguration.applicationProtocols = NIOHTTP2SupportedALPNProtocols
let bootstrap = NIOTSListenerBootstrap(group: loopGroup)
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEPORT), value: 1)
.childChannelInitializer { channel in
let sslContext: NIOSSLContext
let tlsHandler: NIOSSLServerHandler
do {
sslContext = try NIOSSLContext(configuration: tlsConfiguration)
tlsHandler = NIOSSLServerHandler(context: sslContext)
} catch {
print("[HTTP2PROXY] Could not configure TLS")
return channel.close(mode: .all)
}
return channel.pipeline.addHandler(tlsHandler, name: "TLS_Handler").flatMap {
print("[HTTP2PROXY] TLSHandler added to pipeline")
print("[HTTP2PROXY] Configuring pipeline for Http/1.1 and Http/2")
return channel.configureCommonHTTPServerPipeline(h2ConnectionChannelConfigurator: nil) { streamChannel in
return streamChannel.pipeline.addHandlers([DebugInboundEventsHandler(), DebugOutboundEventsHandler()]).flatMap {
print("[HTTP2PROXY] Event debugger handlers added")
return streamChannel.pipeline.addHandler(HTTPResponseCompressor(), name: "ResponseCompressor")
}.flatMap {
print("[HTTP2PROXY] HTTPResponseCompressor added to pipeline")
return streamChannel.pipeline.addHandler(CustomHttp1Handler(hlsRequestHandler: self.hlsRequestHandler), name: "Custom_Http1")
}.flatMap {
print("[HTTP2PROXY] Custom Http1Handler added to pipeline")
return streamChannel.pipeline.addHandler(ErrorHandler())
}
}
}
}
.childChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1)
.childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
.childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEPORT), value: 1)
do {
let serverChannel = try bootstrap.bind(host: Http2Proxy.host, port: Http2Proxy.port).wait()
print("[HTTP2PROXY] Server Channel bound to: \(serverChannel.localAddress!)")
}
catch {
try! loopGroup.syncShutdownGracefully()
print("[HTTP2PROXY] Failed to start channel: \(error)")
}服务器使用Http/2上的Https正确地工作和处理请求,甚至在请求时使用gzip响应。那就太好了。但是我在日志中看到,对于每个传入请求,管道都正在重新配置(例如,对附加处理程序的转义被一次又一次地调用)。它应该是这样工作的吗?据我所知,我不会在任何地方关闭上下文/通道。这个代理是否为每个请求设置了一个新管道,而我是否错过了通过同一个通道(和管道)发送大量请求的Http/2方法?或者,这实际上是它的工作方式吗?感觉不太理想.
日志:
10:21:15.760 [HTTP2PROXY] Server Channel bound to: [IPv4]127.0.0.1/127.0.0.1:50001
10:22:47.813 [HTTP2PROXY] TLSHandler added to pipeline
10:22:47.813 [HTTP2PROXY] Configuring pipeline for Http/1.1 and Http/2
10:22:47.837 [HTTP2PROXY] Event debugger handlers added
10:22:47.838 [HTTP2PROXY] HTTPResponseCompressor added to pipeline
10:22:47.838 [HTTP2PROXY] Custom Http1Handler added to pipeline
10:22:47.853 [HTTP2PROXY] Event debugger handlers added
10:22:47.853 [HTTP2PROXY] HTTPResponseCompressor added to pipeline
10:22:47.853 [HTTP2PROXY] Custom Http1Handler added to pipeline
10:22:47.854 [HTTP2PROXY] Event debugger handlers added
10:22:47.854 [HTTP2PROXY] HTTPResponseCompressor added to pipeline
10:22:47.854 [HTTP2PROXY] Custom Http1Handler added to pipeline
10:22:47.860 [HTTP2PROXY] Event debugger handlers added
10:22:47.860 [HTTP2PROXY] HTTPResponseCompressor added to pipeline
10:22:47.860 [HTTP2PROXY] Custom Http1Handler added to pipeline
10:22:47.861 [HTTP2PROXY] Event debugger handlers added
10:22:47.861 [HTTP2PROXY] HTTPResponseCompressor added to pipeline
10:22:47.861 [HTTP2PROXY] Custom Http1Handler added to pipeline
10:22:47.927 [HTTP2PROXY] Event debugger handlers added
10:22:47.927 [HTTP2PROXY] HTTPResponseCompressor added to pipeline
10:22:47.927 [HTTP2PROXY] Custom Http1Handler added to pipeline记录context.channel.pipeline.debugDescription会给出:
10:30:41.083 [HTTP2PROXY] Pipeline config:
ChannelPipeline[ObjectIdentifier(0x00000002804d6fd0)]:
[I] ↓↑ [O]
HTTP2FramePayloadToHTTP1ServerCodec ↓↑ HTTP2FramePayloadToHTTP1ServerCodec [handler0]
HTTPResponseCompressor ↓↑ HTTPResponseCompressor [ResponseCompressor]
CustomHttp1Handler ↓↑ [Custom_Http1]
ErrorHandler ↓↑ [handler1]
10:30:41.087 [HTTP2PROXY] Pipeline config:
ChannelPipeline[ObjectIdentifier(0x00000002804d7160)]:
[I] ↓↑ [O]
HTTP2FramePayloadToHTTP1ServerCodec ↓↑ HTTP2FramePayloadToHTTP1ServerCodec [handler0]
HTTPResponseCompressor ↓↑ HTTPResponseCompressor [ResponseCompressor]
CustomHttp1Handler ↓↑ [Custom_Http1]
ErrorHandler ↓↑ [handler1]
10:30:41.090 [HTTP2PROXY] Pipeline config:
ChannelPipeline[ObjectIdentifier(0x00000002804d7610)]:
[I] ↓↑ [O]
HTTP2FramePayloadToHTTP1ServerCodec ↓↑ HTTP2FramePayloadToHTTP1ServerCodec [handler0]
HTTPResponseCompressor ↓↑ HTTPResponseCompressor [ResponseCompressor]
CustomHttp1Handler ↓↑ [Custom_Http1]
ErrorHandler ↓↑ [handler1]
10:30:41.100 [HTTP2PROXY] Pipeline config:
ChannelPipeline[ObjectIdentifier(0x00000002804d71b0)]:
[I] ↓↑ [O]
HTTP2FramePayloadToHTTP1ServerCodec ↓↑ HTTP2FramePayloadToHTTP1ServerCodec [handler0]
HTTPResponseCompressor ↓↑ HTTPResponseCompressor [ResponseCompressor]
CustomHttp1Handler ↓↑ [Custom_Http1]
ErrorHandler ↓↑ [handler1]所以每次输油管道的objectIdentifier是不同的.
发布于 2021-09-14 12:17:03
这个问题是在https://forums.swift.org/t/swift-nio-based-proxy-reconfigures-pipeline-on-every-incoming-request/52043论坛上处理的。
Lukasa的答复:
,这是预期的行为。HTTP/2是多路复用的:这意味着您可以在同一个TCP连接上运行多个请求/响应序列。这在SwiftNIO HTTP/2中以“流通道初始化器”的形式得到了体现:每创建一个流就调用一次。这里的流通道初始化器是向configureCommonHTTPServerPipeline传递的尾随闭包。如果您只想创建处理程序一次,您可以这样做。但是现在您的处理程序需要支持涉及多个并发请求和响应。
https://stackoverflow.com/questions/69141348
复制相似问题