ios - 基于 Swift-NIO 的代理在每个传入请求上重新配置管道
问题描述
我正在使用 Swift-NIO 为 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)")
}
服务器使用 Https over Http/2 正确工作和处理请求,甚至在被询问时 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每次都不一样...
解决方案
这个问题是在 swift 论坛上处理的 https://forums.swift.org/t/swift-nio-based-proxy-reconfigures-pipeline-on-every-incoming-request/52043
卢卡萨的回答:
这是预期的行为。HTTP/2 是多路复用的:这意味着您可以在同一个 TCP 连接上运行多个请求/响应序列。这在 SwiftNIO HTTP/2 中以“流通道初始化器”的形式体现:每个流创建都会调用一次。这里的流通道初始化器是传递给 configureCommonHTTPServerPipeline 的尾随闭包。
如果您只想创建一次处理程序,您可以这样做。但是现在您的处理程序需要支持参与多个并发请求和响应。
推荐阅读
- python - Django在表单中静态添加字段
- python - 如何通过云功能将 GCP 的安全中心资产导出到云存储?
- javascript - 触摸事件未在移动设备上触发
- ansible - 如何在 ansible 中使用 {{ item }}?
- php - 根据 WooCommerce 中的用户角色和购物车总数更改结帐时的订单按钮文本
- apache-spark - Glue PySpark 作业因资源问题而失败
- vb.net - VB.Net 如何在等待外部 Web 服务数据加载时释放 UI
- python - Python plotly - 向图例添加水平线
- html - 响应式卡片菜单内容溢出
- html - 如何用 react.js 实现这一点?