当前位置: 首页 > 后端技术 > Node.js

HttpTunnelServer,从源码看Springboot是如何实现双向数据交互的

时间:2023-04-03 23:48:13 Node.js

Tunnel是什么?Tunnel存在的意义就是利用http协议来传输非http协议的内容。使用fiddler4抓包时,经常会看到类似Tunnel的包。打开后你会发现没有标准的http协议模式,没有http头,包体也和HTTP协议包体不同。Tunnel可以作为服务端和客户端的双向通信,解决了http1.1中服务端不能主动向客户端发送信息的问题。Springboot中如何实现Tunnel?Springboot提供了HttpTunnelServer来提供Tunnel等功能。我们可以先看看它的源码publicHttpTunnelServer(TargetServerConnectionserverConnection){Assert.notNull(serverConnection,"ServerConnectionmustnotbenull");this.serverConnection=serverConnection;}从构造方法可以看出,传入了一个TargetServerConnection实例,TargetServerConnection是一个函数式接口。@FunctionalInterfacepublicinterfaceTargetServerConnection{ByteChannelopen(inttimeout)throwsIOException;}在源码中,有一个该接口的现类SocketTargetServerConnectionpublicclassSocketTargetServerConnectionimplementsTargetServerConnection{publicSocketTargetServerConnection(PortProviderportProvider){Assert.notNull(portProvider,"PortProvidermustnotbe无效的”);this.portProvider=portProvider;}@OverridepublicByteChannelopen(intsocketTimeout)throwsIOException{SocketAddress地址=newInetSocketAddress(this.portProvider.getPort());logger.trace(LogMessage.format("在%s上打开到目标服务器的隧道连接",address));SocketChannel通道=SocketChannel.open(地址);channel.socket().setSoTimeout(socketTimeout);返回新的TimeoutAwareChannel(通道);}......}//SocketTargetServerConnection的构造函数传入函数接口PortProvider,//是一个函数接口@FunctionalInterfacepub来获取端口licinterfacePortProvider{/***返回端口号。*@returntheportnumber*/intgetPort();}显然,这个方法是为了Tunnel与其他服务交互而提供的。SocketTargetServerConnection的open函数是Openaport与远程端口交互Springboot自带的测试代码中@BeanDispatcherFilterfilter(AnnotationConfigServletWebServerApplicationContextcontext){TargetServerConnectionconnection=newSocketTargetServerConnection(()->context.getWebServer().getPort());HttpTunnelServerserver=newHttpTunnelServer//(连接);对端端口,定义一个HttpTunnelServerHandlerMappermapper=newUrlHandlerMapper("/httptunnel",newHttpTunnelServerHandler(server));//创建处理程序Collectionmappers=Collections.singleton(mapper);//创建单例Dispatcherdispatcher=newDispatcher(AccessManager.PERMIT_ALL,mappers);//创建处理任务分发returnnewDispatcherFilter(dispatcher);//监听和分发处理任务}//HttpTunnelServerHandler.javapublicclassHttpTunnelServerHandlerimplementsHandler{privateHttubHtpTunnelServerHandlerHandler(HttpTunnelServerserver){Assert.notNull(server,"Servermustnotbenull");this.server=服务器;}@Overridepublicvoidhandle(ServerHttpRequestrequest,ServerHttpResponseresponse)throwsIOException{this.server.handle(request,response);}}//其中Handler也是一个函数式接口@FunctionalInterfacepublicinterfaceHandler{/***处理请求。*@paramrequest请求*@paramresponse响应*@throwsIOException在I/O错误的情况下*/voidhandle(ServerHttpRequestrequest,ServerHttpResponseresponse)throwsIOException;此时,HttpTunnelServer首先通过将数据包封装到Servlet中,与远程服务器建立connet连接。连接建立成功后,通过Http方式将数据包发送出去。有了HttpTunnelServer,我们就可以与远程服务器Server集成炸鸡辣子鸡原创文章,转载请注明出处