Set up HTTP/2 server with Spring Boot 【基于Spring boot搭建http2.0服务器】
1. Server side
With spring boot, we can set up a http server easily. Restcontroller make it easier to provide REST apis.
今天博主决定体验下HTTP/2。用spring boot搭建http服务相对容易,于是开始动手编写。
Entrance (入口)
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(AppConfig.class, args);
}
}
Configuration (配置)
Marked sentence enables http/2
标记部分可以为undertow容器开启H2的支持
@Configuration
public class BaseConfig {
@Bean
public EmbeddedServletContainerFactory servletContainer() {
UndertowEmbeddedServletContainerFactory factory = new UndertowEmbeddedServletContainerFactory();
factory.addBuilderCustomizers(builder -> builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true));
return factory;
}
}
Controller
@RestController
public class SimpleController {
@RequestMapping("/greeting")
public String greeting(@RequestParam(value="name", defaultValue="World") String name) {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('~')");
String message = exp.getValue(String.class);
return message;
}
@RequestMapping("/hello")
public ResponseEntity hello(@RequestParam(value="name", defaultValue = "SYSTEM") String name) {
return ResponseEntity.ok().body("Hello from " + name);
}
}
Let's try it! Start server, use okhttp client to visit one link localhost:8080/greeting, and then wait for the response. Surprisingly, the http protocol is still http/1.1. What happened? Why there is no magic after enabling http/2 support? Well, JDK 8 still lacks good support for http/2.
编写完成,启动服务器,用okhttp客户端访问其中一个url。虽然有所期待,然而并无惊喜,从响应来看协议还是1.1。经过一番调查发现,即便是最新的JDK8,对H2的支持也不好。(听说JDK9会支持)
The good news is, we can start server with alpn jar to make up for this limitation. Let's config the following argument in jvm. Remember to choose the proper jar version that matches your jre version. https://www.eclipse.org/jetty/documentation/9.4.x/alpn-chapter.html#alpn-starting
好在Jetty alpn为JDK 8提供了alpn支持,我们在jvm的启动参数里加上下面这句
-Xbootclasspath/p:{maven dir}/repository/org/mortbay/jetty/alpn/alpn-boot/8.1.3.v20150130/alpn-boot-8.1.3.v20150130.jar
Again, the response shows the protocol is http/1.1. Thanks to the blog https://daniel.haxx.se/blog/2015/03/06/tls-in-http2/, it reminds us most existing servers only speak http/2 via TLS.
OK, let's make our Spring boot support https as well. First generate a SSL cert, and then configure the keystore infos in spring properties.
可是重启服务器之后,协议还是1.1。这次又是为什么呢?原来,虽说h2的规范中并没有强行要求一定要在传输层加密,然而现有实现基本都建立在安全传输层协议上的。 所以要搭建H2服务器,我们还差最后一步 ------ 支持安全传输层协议。
将http改为https很容易,创建证书,给spring加上相关配置,重启服务便完成了。
server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=123456 server.ssl.keyStoreType=PKCS12
Finally, an HTTP/2 is running successfully.
一波三折,H2服务器终于搞定。
2. Client side
Next, let's use okhttp client to experience http/2.
Using default okhttp client will encounter this error.
接着,用okhttp客户端来感受下新协议。出师不利,一开始访问就遇到下面的错误。
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Luckily, we can customize unsafe http client to trust self signed cert.
刚才给服务器配的证书是自签名的,客户端不让轻易连接。暂时不想动服务器的证书,那么就降低客户端安全性吧,按照下面的代码配置一个安全性较低的客户端。
private static OkHttpClient getUnsafeOkHttpClient() {
try {
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
};
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {trustManager};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
builder.sslSocketFactory(sslSocketFactory, trustManager);
builder.hostnameVerifier((hostname, session) -> true);
return builder.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Then, the client prompts below info. So we add the same argument in client side jvm as what has been done in server side.
再次访问服务器,出现了新的警告。提示很明显,所以我们参照之前的方式给客户端jvm也加上启动参数。
Apr 27, 2017 5:19:43 PM okhttp3.internal.platform.Platform log INFO: ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path? Apr 27, 2017 5:19:43 PM okhttp3.internal.platform.Platform log INFO: ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path?
After so many fails, the expected result finally appears in the console. Okhttp client tells the current prototol becomes h2 (http/2.0).
最后,终端上显示出了期待已久的H2
h2 Time consumed in ts 2159 h2 Time consumed in ts 2160
3. Some benefits after using h2 client
https://http2.github.io/faq/#why-revise-http this passage already explains a lot.
Why just one TCP connection?
With HTTP/1, browsers open between four and eight connections per origin. Since many sites use multiple origins, this could mean that a single page load opens more than thirty connections.
One application opening so many connections simultaneously breaks a lot of the assumptions that TCP was built upon; since each connection will start a flood of data in the response, there’s a real risk that buffers in the intervening network will overflow, causing a congestion event and retransmits.
Additionally, using so many connections unfairly monopolizes network resources, “stealing” them from other, better-behaved applications (e.g., VoIP).
While only one communication is built per origin, it consumes less resource in both client and server.
Here we conduct a simple check of the network communications.
H2的优点很多,这里主要验证下连接开销这块。
With http 1.1
用1.1客户端给服务器发送几十个请求,可以看到许多tcp建立了起来,这同时增加了客户端和服务器的开销。
C:\Users\??>netstat | find "8080" TCP 127.0.0.1:8080 ??:10951 ESTABLISHED TCP 127.0.0.1:8080 ??:10952 ESTABLISHED TCP 127.0.0.1:8080 ??:10953 ESTABLISHED TCP 127.0.0.1:8080 ??:10954 ESTABLISHED TCP 127.0.0.1:8080 ??:10955 ESTABLISHED TCP 127.0.0.1:8080 ??:10956 ESTABLISHED TCP 127.0.0.1:8080 ??:10957 ESTABLISHED TCP 127.0.0.1:8080 ??:10958 ESTABLISHED TCP 127.0.0.1:8080 ??:10959 ESTABLISHED TCP 127.0.0.1:8080 ??:10960 ESTABLISHED TCP 127.0.0.1:10951 ??:8080 ESTABLISHED TCP 127.0.0.1:10952 ??:8080 ESTABLISHED TCP 127.0.0.1:10953 ??:8080 ESTABLISHED TCP 127.0.0.1:10954 ??:8080 ESTABLISHED TCP 127.0.0.1:10955 ??:8080 ESTABLISHED TCP 127.0.0.1:10956 ??:8080 ESTABLISHED TCP 127.0.0.1:10957 ??:8080 ESTABLISHED TCP 127.0.0.1:10958 ??:8080 ESTABLISHED TCP 127.0.0.1:10959 ??:8080 ESTABLISHED TCP 127.0.0.1:10960 ??:8080 ESTABLISHED
With http 2.0
使用2.0客户端,果然只有一个连接了。
C:\Users\??>netstat | find "8080" TCP 127.0.0.1:8080 ??:11571 ESTABLISHED TCP 127.0.0.1:11571 ??:8080 ESTABLISHED
The connection count reduced obviously after changing the protocol.
Apart from that, slow start, one congestion controll stratege, happens only one during the lifecycle. It's good the client performance and network.
由于同一个连接复用,慢启动只发生一次,这对客户端和网络也有一定好处。
Set up HTTP/2 server with Spring Boot 【基于Spring boot搭建http2.0服务器】的更多相关文章
- Spring boot 基于Spring MVC的Web应用和REST服务开发
Spring Boot利用JavaConfig配置模式以及"约定优于配置"理念,极大简化了基于Spring MVC的Web应用和REST服务开发. Servlet: package ...
- Spring Boot 基于Spring Initializer 的快速构建 day02
一.基于Spring Initializr 快速构建Spring Boot项目(快速) 备注:需要联网 这是使用Intellij Idea快速构建可以为我们省去大量的pom.xml配置时间,简单操作, ...
- Spring Cloud 微服务中搭建 OAuth2.0 认证授权服务
在使用 Spring Cloud 体系来构建微服务的过程中,用户请求是通过网关(ZUUL 或 Spring APIGateway)以 HTTP 协议来传输信息,API 网关将自己注册为 Eureka ...
- Spring 学习——基于Spring WebSocket 和STOMP实现简单的聊天功能
本篇主要讲解如何使用Spring websocket 和STOMP搭建一个简单的聊天功能项目,里面使用到的技术,如websocket和STOMP等会简单介绍,不会太深,如果对相关介绍不是很了解的,请自 ...
- 初学 Spring MVC(基于 Spring in Action)
Spring MVC(Model-View-Controller) 当你看到本博文时,我猜你可能正面临着我已探索过的问题. 同其他博主一样,我先按照书上详细的介绍一下 Spring MVC,也是为了自 ...
- Spring Cloud Alibaba与Spring Boot、Spring Cloud之间不得不说的版本关系
这篇博文是临时增加出来的内容,主要是由于最近连载<Spring Cloud Alibaba基础教程>系列的时候,碰到读者咨询的大量问题中存在一个比较普遍的问题:版本的选择.其实这类问题,在 ...
- Spring MVC 到 Spring Boot 的简化之路(山东数漫江湖)
背景 从Servlet技术到Spring和Spring MVC,开发Web应用变得越来越简捷.但是Spring和Spring MVC的众多配置有时却让人望而却步,相信有过Spring MVC开发经验的 ...
- Spring boot与Spring cloud之间的关系
Spring boot 是 Spring 的一套快速配置脚手架,可以基于spring boot 快速开发单个微服务,Spring Boot,看名字就知道是Spring的引导,就是用于启动Spring的 ...
- Spring MVC 到 Spring BOOT 的简化之路
背景 Spring vs Spring MVC vs Spring Boot Spring FrameWork Spring 还能解决什么问题 Spring MVC 为什么需要Spring Boot ...
随机推荐
- 读书笔记 effective c++ Item 34 区分接口继承和实现继承
看上去最为简单的(public)继承的概念由两个单独部分组成:函数接口的继承和函数模板继承.这两种继承之间的区别同本书介绍部分讨论的函数声明和函数定义之间的区别完全对应. 1. 类函数的三种实现 作为 ...
- linux系统和Windows系统共存
最近接触了linux系统,因为对linux系统一直存在一种敬畏之心,所以决定研究研究 那么今天我在这里呢是要和大家分享一下在Windows存在的情况下安装双系统linux 那么第一步呢,就是斤BIOS ...
- 设计模式的征途—1.单例(Singleton)模式
单例模式属于创建型模式的一种,创建型模式是一类最常用的设计模式,在软件开发中应用非常广泛.创建型模式将对象的创建和使用分离,在使用对象时无需关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修 ...
- Nginx网站使用CDN之后禁止用户真实IP访问的方法
做过面向公网WEB的运维人员经常会遇见恶意扫描.拉取.注入等图谋不轨的行为,对于直接对外的WEB服务器,我们可以直接通过 iptables .Nginx 的deny指令或是程序来ban掉这些恶意请求. ...
- Unity SteamVR插件集成
重要组件 SteamVR_Camera VR摄像机,主要功能是将Unity摄像机的画面进行变化,形成Vive中的成像画面 使用方法: l 在任一个摄像机上增加脚本 l 点击Expand按钮 完成以上操 ...
- 函数调用过程&生成器解释
摘自马哥解答,感谢. 函数调用过程: 假设程序是单进程,单执行流,在某一时刻,能运行的程序流只能有一个.但函数调用会打开新的执行上下文,因此,为了确保main函数可以恢复现场,在main函数调用其它函 ...
- iOS9,10没有问题,iOS8上面一登录就崩溃,原因Assets的问题
在项目中开发中,打包成一个ipa的包,发现iOS9,10,运行非常流畅,iOS8上面一运行就崩溃,找了好久,才找到原因竟然是Assets的问题,一开始我把ipa包放在蒲公英上面托管扫码下载的,用iTu ...
- MongoDB基础教程系列--第二篇 MongoDB基本操作(一)
1.安装环境 在官网上下载MongoDB的最新版本,根据自身Windows版本下载正确的MongoDB版本.下载后,双击32位或者64位.msi文件,按操作提示安装就可以了. 说明: 32 位版本的 ...
- 老李分享: 并行计算基础&编程模型与工具 1
老李分享: 并行计算基础&编程模型与工具 在当前计算机应用中,对高速并行计算的需求是广泛的,归纳起来,主要有三种类型的应用需求: 计算密集(Computer-Intensive)型应用,如 ...
- js正则表达式匹配字符串与优化过程
前言 有时候需要实现对js源文件中的url字符串做拦截预处理,或者前端js语法高亮,或者需要对动态加载的关键源码做混淆保护,在某些步骤实现之前,有一个步骤是需要提炼出所有的合法字符串. 目标:检测源文 ...