您现在的位置是:首页 > 文章详情

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

日期:2020-11-03点击:382

Tunnel是什么?

Tunnel存在的意义,就是使用http协议来传输非http协议的内容,在使用fiddler4抓包的时候,常常会看见Tunnel这样的包,打开之后会发现里面没有标准http协议的模式,没有http头,包体也和http协议包体不相同。

Tunnel可以用来做服务器和客户端进行双向交流,这就解决了http1.1中无法实现服务器主动给客户端发送信息的问题。

Springboot中如何实现Tunnel?

Springboot中提供了HttpTunnelServer来提供Tunnel这样的功能,我们可以先来看一看它的源码

public HttpTunnelServer(TargetServerConnection serverConnection) { Assert.notNull(serverConnection, "ServerConnection must not be null"); this.serverConnection = serverConnection; } 

从构造方法中我们可以看出,传入了一个TargetServerConnection实例,而TargetServerConnection是一个函数式接口。

@FunctionalInterface public interface TargetServerConnection { ByteChannel open(int timeout) throws IOException; } 

在源码中,有一个该接口的实现类SocketTargetServerConnection

public class SocketTargetServerConnection implements TargetServerConnection { public SocketTargetServerConnection(PortProvider portProvider) { Assert.notNull(portProvider, "PortProvider must not be null"); this.portProvider = portProvider; } @Override public ByteChannel open(int socketTimeout) throws IOException { SocketAddress address = new InetSocketAddress(this.portProvider.getPort()); logger.trace(LogMessage.format("Opening tunnel connection to target server on %s", address)); SocketChannel channel = SocketChannel.open(address); channel.socket().setSoTimeout(socketTimeout); return new TimeoutAwareChannel(channel); } ... ... } // SocketTargetServerConnection的构造函数传入的是函数式接口PortProvider, // 是一个获取port的函数式接口 @FunctionalInterface public interface PortProvider { /** * Return the port number. * @return the port number */ int getPort(); } 

很明显,这个方法是提供的该服务于其他服务进行Tunnel交互的,SocketTargetServerConnection的open函数是打开一个端口与远程端口进行交互。在Springboot自己的测试代码中

@Bean DispatcherFilter filter(AnnotationConfigServletWebServerApplicationContext context) { TargetServerConnection connection = new SocketTargetServerConnection( () -> context.getWebServer().getPort()); HttpTunnelServer server = new HttpTunnelServer(connection); // 在webServer的对等端口,定义了一个HttpTunnelServer HandlerMapper mapper = new UrlHandlerMapper("/httptunnel", new HttpTunnelServerHandler(server)); // 创建一个处理器 Collection<HandlerMapper> mappers = Collections.singleton(mapper); // 创建单例 Dispatcher dispatcher = new Dispatcher(AccessManager.PERMIT_ALL, mappers); // 创建处理任务分发 return new DispatcherFilter(dispatcher); // 监听并分发处理任务 } 
// HttpTunnelServerHandler.java public class HttpTunnelServerHandler implements Handler { private HttpTunnelServer server; public HttpTunnelServerHandler(HttpTunnelServer server) { Assert.notNull(server, "Server must not be null"); this.server = server; } @Override public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException { this.server.handle(request, response); } } // 其中Handler也是一个函数式接口 @FunctionalInterface public interface Handler { /** * Handle the request. * @param request the request * @param response the response * @throws IOException in case of I/O errors */ void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException; } 

也就是说,在需要与远程进行Tunnel隧道传输的时候,HttpTunnelServer通过将数据包封装进Servlet中的方法,首先与远端服务器建立connet连接,连接建立成功以后,将数据包再通过Http的方法传出去。

有了HttpTunnelServer,我们就可以和远端集成服务器双向交流

炒鸡辣鸡原创文章,转载请注明来源

原文链接:https://my.oschina.net/u/3773302/blog/4701242
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章