HttpTunnelServer,从源码看Springboot如何实现双向数据交互
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,我们就可以和远端集成服务器双向交流
炒鸡辣鸡原创文章,转载请注明来源

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
go-zero 是如何追踪你的请求链路的
go-zero 是如何追踪你的请求链路 微服务架构中,调用链可能很漫长,从 http 到 rpc ,又从 rpc 到 http 。而开发者想了解每个环节的调用情况及性能,最佳方案就是 全链路跟踪。 追踪的方法就是在一个请求开始时生成一个自己的 spanID ,随着整个请求链路传下去。我们则通过这个 spanID 查看整个链路的情况和性能问题。 下面来看看 go-zero 的链路实现。 代码结构 spancontext:保存链路的上下文信息「traceid,spanid,或者是其他想要传递的内容」 span:链路中的一个操作,存储时间和某些信息 propagator: trace 传播下游的操作「抽取,注入」 noop:实现了空的 tracer 实现 概念 SpanContext 在介绍 span 之前,先引入 context 。SpanContext 保存了分布式追踪的上下文信息,包括 Trace id,Span id 以及其它需要传递到下游的内容。OpenTracing 的实现需要将 SpanContext 通过某种协议 进行传递,以将不同进程中的 Span 关联到同一个 Trace...
- 下一篇
缓存穿透、缓存击穿和缓存雪崩
作者 | xiaowei123 出处 | https://0x9.me/Lg9yp 在Redis缓存中有三个必须要知道概念:「缓存穿透、缓存击穿和缓存雪崩。」 缓存穿透 什么是缓存穿透呢?它是指当用户在查询一条数据的时候,而此时数据库和缓存却没有关于这条数据的任何记录,而这条数据在缓存中没找到就会向数据库请求获取数据。它拿不到数据时,是会一直查询数据库,这样会对数据库的访问造成很大的压力。 如:用户查询一个 id = -1 的商品信息,一般数据库 id 值都是从 1 开始自增,很明显这条信息是不在数据库中,当没有信息返回时,会一直向数据库查询,给当前数据库的造成很大的访问压力。 这时候我们要想一想,该如何解决这个问题呢?o(╥﹏╥)o 一般我们可以想到从缓存开始出发,想如果我们给缓存设置一个如果当前数据库不存在的信息,把它缓存成一个空对象,返回给用户。 ^_^没错,这是一个解决方案,也就是我们常说的缓存空对象(代码维护简单,但是效果不是很好)。 Redis 也为我们提供了一种解决方案,那就是布隆过滤器(代码维护比较复杂,效果挺好的)。 「那接下来,二哈先解释下这两种方案:」 缓存空对象...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8编译安装MySQL8.0.19
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合Redis,开启缓存,提高访问速度