热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于java:netty系列之搭建客户端使用http11的方式连接http2服务器

对于http2协定来说,它的底层跟http1.1是齐全不同的,然而为了兼容http1.1协定,http2提供了一个从http1.1降级到http2的形式,这个形式叫做cleartextupgrade,也能够简称为h2c。
简介

对于http2协定来说,它的底层跟http1.1是齐全不同的,然而为了兼容http1.1协定,http2提供了一个从http1.1降级到http2的形式,这个形式叫做cleartext upgrade,也能够简称为h2c。

在netty中,http2的数据对应的是各种http2Frame对象,而http1的数据对应的是HttpRequest和HttpHeaders。一般来说要想从客户端发送http2音讯给反对http2的服务器,那么须要发送这些http2Frame的对象,那么可不可以像http1.1这样发送HttpRequest对象呢?

明天的文章将会给大家揭秘。

应用http1.1的形式解决http2

netty当然思考到了客户的这种需要,所以提供了两个对应的类,别离是:InboundHttp2ToHttpAdapter和HttpToHttp2ConnectionHandler。

他们是一对办法,其中InboundHttp2ToHttpAdapter将接管到的HTTP/2 frames 转换成为HTTP/1.x objects,而HttpToHttp2ConnectionHandler则是相同的将HTTP/1.x objects转换成为HTTP/2 frames。 这样咱们在程序中只须要解决http1的对象即可。

他们的底层实际上调用了HttpConversionUtil类中的转换方法,将HTTP2对象和HTTP1对象进行转换。

解决TLS连贯

和服务器一样,客户端的连贯也须要辨别是TLS还是clear text,TLS简略点,只须要解决HTTP2数据即可,clear text简单点,须要思考http降级的状况。

先看下TLS的连贯解决。

首先是创立SslContext,客户端的创立和服务器端的创立没什么两样,这里要留神的是SslContextBuilder调用的是forClient()办法:

SslProvider provider =
                    SslProvider.isAlpnSupported(SslProvider.OPENSSL)? SslProvider.OPENSSL : SslProvider.JDK;
            sslCtx = SslContextBuilder.forClient()
                    .sslProvider(provider)
                    .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
                    // 因为咱们的证书是自生成的,所以须要信赖放行
                    .trustManager(InsecureTrustManagerFactory.INSTANCE)
                    .applicationProtocolConfig(new ApplicationProtocolConfig(
                            Protocol.ALPN,
                            SelectorFailureBehavior.NO_ADVERTISE,
                            SelectedListenerFailureBehavior.ACCEPT,
                            ApplicationProtocolNames.HTTP_2,
                            ApplicationProtocolNames.HTTP_1_1))
                    .build();

而后将sslCtx的newHandler办法传入到pipeline中:

pipeline.addLast(sslCtx.newHandler(ch.alloc(), CustHttp2Client.HOST, CustHttp2Client.PORT));

最初退出ApplicationProtocolNegotiationHandler,用于TLS扩大协定的协商:

pipeline.addLast(new ApplicationProtocolNegotiationHandler("") {
            @Override
            protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
                if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
                    ChannelPipeline p = ctx.pipeline();
                    p.addLast(connectionHandler);
                    p.addLast(settingsHandler, responseHandler);
                    return;
                }
                ctx.close();
                throw new IllegalStateException("未知协定: " + protocol);
            }
        });

如果是HTTP2协定,则须要向pipline中退出三个handler,别离是connectionHandler,settingsHandler和responseHandler。

connectionHandler用于解决客户端和服务器端的连贯,这里应用HttpToHttp2ConnectionHandlerBuilder来构建一个上一节提到的HttpToHttp2ConnectionHandler,用来将http1.1对象转换成为http2对象。

Http2Connection cOnnection= new DefaultHttp2Connection(false);
        cOnnectionHandler= new HttpToHttp2ConnectionHandlerBuilder()
                .frameListener(new DelegatingDecompressorFrameListener(
                        connection,
                        new InboundHttp2ToHttpAdapterBuilder(connection)
                                .maxContentLength(maxContentLength)
                                .propagateSettings(true)
                                .build()))
                .frameLogger(logger)
                .connection(connection)
                .build();

然而连贯其实是双向的,HttpToHttp2ConnectionHandler是将http1.1转换成为http2,它实际上是一个outbound处理器,咱们还须要一个inbound处理器,用来将接管到的http2对象转换成为http1.1对象,这里通过增加framelistener来实现。

frameListener传入一个DelegatingDecompressorFrameListener,其外部又传入了前一节介绍的InboundHttp2ToHttpAdapterBuilder用来对http2对象进行转换。

settingsHandler用来解决Http2Settings inbound音讯,responseHandler用来解决FullHttpResponse inbound音讯。

这两个是自定义的handler类。

解决h2c音讯

从下面的代码能够看出,咱们在TLS的ProtocolNegotiation中只解决了HTTP2协定,如果是HTTP1协定,间接会报错。如果是HTTP1协定,则能够通过clear text upgrade来实现,也就是h2c协定。

咱们看下h2c须要增加的handler:

    private void configureClearText(SocketChannel ch) {
        HttpClientCodec sourceCodec = new HttpClientCodec();
        Http2ClientUpgradeCodec upgradeCodec = new Http2ClientUpgradeCodec(connectionHandler);
        HttpClientUpgradeHandler upgradeHandler = new HttpClientUpgradeHandler(sourceCodec, upgradeCodec, 65536);

        ch.pipeline().addLast(sourceCodec,
                              upgradeHandler,
                              new CustUpgradeRequestHandler(this),
                              new UserEventLogger());
    }

首先增加的是HttpClientCodec作为source编码handler,而后增加HttpClientUpgradeHandler作为upgrade handler。最初增加自定义的CustUpgradeRequestHandler和事件记录器UserEventLogger。

自定义的CustUpgradeRequestHandler负责在channelActive的时候,创立upgradeRequest并发送到channel中。

因为upgradeCodec中曾经蕴含了解决http2连贯的connectionHandler,所以还须要手动增加settingsHandler和responseHandler。

ctx.pipeline().addLast(custHttp2ClientInitializer.settingsHandler(), custHttp2ClientInitializer.responseHandler());
发送音讯

handler配置好了之后,咱们就能够间接以http1的形式来发送http2音讯了。

首先发送一个get申请:

// 创立一个get申请
                FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, GETURL, Unpooled.EMPTY_BUFFER);
                request.headers().add(HttpHeaderNames.HOST, hostName);
                request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), scheme.name());
                request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
                request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE);
                responseHandler.put(streamId, channel.write(request), channel.newPromise());

而后是一个post申请:

// 创立一个post申请
                FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, POST, POSTURL,
                        wrappedBuffer(POSTDATA.getBytes(CharsetUtil.UTF_8)));
                request.headers().add(HttpHeaderNames.HOST, hostName);
                request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), scheme.name());
                request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
                request.headers().add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE);
                responseHandler.put(streamId, channel.write(request), channel.newPromise());

和一般的http1申请没太大区别。

总结

通过应用InboundHttp2ToHttpAdapter和HttpToHttp2ConnectionHandler能够不便的应用http1的办法来发送http2的音讯,十分不便。

本文的例子能够参考:learn-netty4

本文已收录于 http://www.flydean.com/30-netty-http2client-md/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」,懂技术,更懂你!


推荐阅读
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了解决java开源项目apache commons email简单使用报错的方法,包括使用正确的JAR包和正确的代码配置,以及相关参数的设置。详细介绍了如何使用apache commons email发送邮件。 ... [详细]
  • 开发笔记:SpringBoot学习开发web应用
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了SpringBoot学习开发web应用相关的知识,希望对你有一定的参考价值。SpringBoot ... [详细]
  • 在这分布式系统架构盛行的时代,很多互联网大佬公司开源出自己的分布式RPC系统框架,例如:阿里的dubbo,谷歌的gRPC,apache的Thrift。而在我们公司一直都在推荐使用d ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • 如何利用 Myflash 解析 binlog ?
    本文主要介绍了对Myflash的测试,从准备测试环境到利用Myflash解析binl ... [详细]
  • JavaWeb中读取文件资源的路径问题及解决方法
    在JavaWeb开发中,读取文件资源的路径是一个常见的问题。本文介绍了使用绝对路径和相对路径两种方法来解决这个问题,并给出了相应的代码示例。同时,还讨论了使用绝对路径的优缺点,以及如何正确使用相对路径来读取文件。通过本文的学习,读者可以掌握在JavaWeb中正确找到和读取文件资源的方法。 ... [详细]
  • Windows网络编程(一):创建链接文章目录Windows网络编程(一):创建链接一、使用前的 ... [详细]
  • Nettty指南(1):Netty简介
    一、Netty介绍与应用场景1.1Netty的介绍Netty是由JBOSS提供的一个Java开源框架,现为Github上的独立项目。Netty是一个异步的、基于事 ... [详细]
  • 杂谈,微服务API Gateway
    让我们想象一下你正在建立一个使用微服务模式的网上商店,你所用的产品详细信息页面。你需要开发多个版本的产品详情界面:l由服务器端Web应用程序生成的HTM ... [详细]
author-avatar
最好的zixue
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有