基于Spring Boot2.0 & HTTP/2 实现服务器、客户端

这篇具有很好参考价值的文章主要介绍了基于Spring Boot2.0 & HTTP/2 实现服务器、客户端。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

HTTP协议由于其无状态的特性以及超高的普及率,是当下大部分网站选择使用的应用层协议。然而,HTTP/1.x的底层传输方式的几个特性,已经对应用的整体性能产生了负面影响。特别是,HTTP/1.0在每次的TCP连接上只允许发送一次请求,在HTTP/1.1中增加了请求管线,但是这仅仅解决了部分的并发问题,并且仍然存在阻塞的现象,因此需要发送多个请求的HTTP/1.0和HTTP/1.1客户端就与服务器建立多个连接,以达到高并发低延迟的目的。

另外,HTTP请求头中的字段经常重复且冗长,带来不必要的网络流量,并会导致初始的TCP拥塞窗口被快速填满。当在一个新的TCP连接上发送多个请求时,这可能导致更大的延迟。

HTTP/2通过在底层连接上定义更优的HTTP语义来解决这些问题。具体来说,它引入了流、帧的二进制传输方式,每个请求由唯一的流id标识,允许在同一个连接上交错地传输请求和响应信息,并对HTTP请求头字段使用高效的压缩编码。它还允许对请求设置优先特权,让更重要的请求更快地完成,从而进一步提高性能。

已经使用HTTP/2协议的网站也有很多,像Google、Twitter、Akamai等这些国外的公司早就支持HTTP/2了,国内的网站比如百度、知乎、新浪、阿里、京东等也都已经全面支持HTTP/2,所以HTTP/2已经过了前期推广的阶段,开始逐渐普及了。


HTTP/2特性

HTTP协议从1991年的HTTP 0.9 到 HTTP 1.0、HTTP 1.1 再到 2015年开始至今的HTTP 2.0,每个版本都带来了惊人的升级体验。HTTP/2的惊人之处可以在这里体验一下,可以感受到相比HTTP 1.1在性能上的大幅提升。

特性

  1. 新的二进制格式:HTTP 1.x的解析是基于文本,HTTP 2.0的解析是基于二进制,更加适用于服务器间信息传输了。
  2. 多路复用(MultiPlexing):也就是连接共享,每个请求都有一个ID,这样在一个连接上可以发送多个请求,并且它们在传输过程中是混杂在一起的,接收方可以根据请求的ID将请求再归属到不同的服务端请求里面。
  3. 请求优先级(request prioritization):HTTP/2中,一个源只有一个连接来实现多路复用,所有资源通过一个连接传输,为了避免线头堵塞(Head Of Line Block),这时资源传输的顺序就更重要了。优先加载重要资源,可以尽快渲染页面,提升用户体验。
  4. header压缩:通信双方各自缓存一份Header fields表,只传输压缩之后的相应编码,避免了重复的header传输。
  5. 服务端推送(server push):这个就很好理解了,HTTP 1.x都是只能从client拉取资源,HTTP/2支持从server端推送资源至client端。

HTPP 2.0的多路复用和HTTP 1.x的长连接的区别

  1. HTTP 1.0中一次请求响应就建立一次连接,用完关闭,每个请求都要建立一个连接。
  2. HTTP 1.1 Pipeling解决方式,也是我们常说的Keep-Alive模式,建立一次连接之后,若干个请求排队串行化单线程处理,后面的请求等待前面的请求返回了获得执行机会,一旦有请求超时等待,后续的请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞(Head-of-Line Blocking)。

Spring Boot 实现 HTTP/2 服务器

本篇主要讨论HTTP/2协议实现,springboot-web具体接口开发已提前准备好。
在Spring Boot应用中常用到的WEB服务器有:Undertow、Jetty、Tomcat三个,使用这三个WEB服务器都能配置出支持HTTP/2的Spring Boot服务,具体步骤参见官方文档。

HTTP/2 与 Jetty
从 Jetty 9.4.8 开始, Conscrypt 库也支持 HTTP/2 。要启用该支持,您的应用程序需要有两个额外的依赖项: org.eclipse.jetty:jetty-alpn-conscrypt-server和org.eclipse.jetty.http2:http2-server.

HTTP/2 与 Tomcat
Tomcat 8.5.x + JDK8版本下支持HTPP/2需要安装相应的本机库。您可以使用 JVM 参数来执行此操作,例如 -Djava.library.path=/usr/local/opt/tomcat-native/lib. 更多信息请参阅 Tomcat 官方文档。
或者使用Tomcat 9.0.x + JDK9版本,也可支持HTTP/2。

HTTP/2 与 Undertow
从Undertow 1.4.0+开始,就可以支持JDK8版本下的HTTP/2,无需其他任何要求。

本篇选用是Undertow,由于SpringBoot内嵌的是tomcat服务器,我们需要在Spring Boot的依赖中排除默认的tomcat服务器,引入undertow服务器,方法是修改项目的POM文件:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!-- 从依赖信息里移除 Tomcat配置 -->
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- 引入undertow服务器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.jboss.xnio</groupId>
            <artifactId>xnio-nio</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.jboss.xnio</groupId>
    <artifactId>xnio-nio</artifactId>
    <version>3.8.7.Final</version>
</dependency>

关于HTTP2中HTTPS说明:

HTTP2.0其实可以支持非HTTPS的,但是现在主流的浏览器像chrome,firefox表示还是只支持基于 TLS 部署的HTTP2.0协议,所以要想升级成HTTP2.0还是先升级HTTPS为好。(我也尝试了只添加HTTP/2配置,不配置HTTPS,使用chrome浏览器访问确实仍为http/1.1,相关配置并未生效)

配置HTTPS:

使用jdk自带keytool生成安全证书(自签名):


keytool -genkeypair -alias certificatekey -keyalg RSA -validity 365 -keystore shfqkeystore.jks

这条命令会在生成keystore后接着生成一个密钥对。
certificatekey是别名,可以自己指定。
RSA是非对称密钥算法,也可以改为 keytool支持的其他密钥算法。
365代表的是证书的有效期,单位天,可以自己指定。
shfqkeystore.jks是keystroe的名称,可以自己指定。

执行该命令后会提示输入密码口令、身份信息,按照提示输入即可,最后选择信任此证书。

基于Spring Boot2.0 & HTTP/2 实现服务器、客户端

完成上述步骤,即会在当前目录生成证书,将证书放在resources目录下。

添加application.yml配置:

server:
  port: 9002  #https默认接口为8443,此处可以自己修改
  ssl:
    key-store: classpath:shfqkeystore.jks
    key-store-password: 123456
    key-password: 123456
    enabled: true

此时使用Chrome访问项目中链接:https://localhost:9002/http2/visit
可以看到可以通过https协议访问,但协议仍为http/1.1

基于Spring Boot2.0 & HTTP/2 实现服务器、客户端

实现HTTPS之后,配置HTTP/2就相当简单了,只需要在application.yml配置中添加
server.http2.enable=true

server:
  port: 9002
  ssl:
    key-store: classpath:rabbitkeystore.jks
    key-store-password: 123456
    key-password: 123456
    enabled: true
  http2:
    enabled: true

此时使用Chrome仍然访问链接:https://localhost:9002/http2/visit
可以看到已经为http/2协议

基于Spring Boot2.0 & HTTP/2 实现服务器、客户端
补充:
1.若网页提示您的连接不是私密连接问题,输入 thisisunsafe 即可(不用管显示在哪里,直接在键盘上输入即可);

2.若您在Chrome的开发者工具中没有显示请求的协议,右键将Protocol项选中即可;

基于Spring Boot2.0 & HTTP/2 实现服务器、客户端


使用java代码实现HTTP/2调用

了解到JDK9之后okhttp3可以支持HTTP/2,于是我们使用springboot配合okhttp3来实现java代码的HTTP/2调用,并将java版本选择为稳定版的JDK11。(JDK自带的Http Client,也要JDK9版本以后才支持HTTP/2,大家也可尝试)

引入pom依赖:
srpingboot:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.6</version>
</parent>

okhttps:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.10.0</version>
</dependency>

将服务器中生成的安全证书copy到该项目的resources目录下。

代码实现:

import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import javax.net.ssl.*;
import java.io.IOException;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class Http2ClientUtil {
    // 服务器ip
    public static String host = "https://127.0.0.1";

    // 服务器端口
    public static int port = 9002;

    private static OkHttpClient client;

    static {
        try {
            initClient();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // GET请求接口不带参数
    public static String doGetNoParams(String path) {
        String result;
        try {
            String url = host + ":" + port + path;
            Request request = new Request.Builder().url(url).build();
            Response response = client.newCall(request).execute();
            result = response.body().string();
            String protocol = response.protocol().name();
            System.out.println("server result:" + result); 
            System.out.println("client protocol:" + protocol); 
        } catch (IOException e) {
            result = "failed";
            e.printStackTrace();
        }
        return result;
    }
	/**
	 * 初始化生成OkHttpClient client
	 */
    public static void initClient() throws Exception {
        // 导入公钥证书
        KeyStore keyStore = KeyStore.getInstance("JKS"); // .jks格式
        Resource resource = new ClassPathResource("shfqkeystore.jks");//路径基于resources
        keyStore.load(resource.getInputStream(), "123456".toCharArray());//密钥口令

        // 初始化证书管理factory
        TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        factory.init(keyStore);

        // 获得X509TrustManager
        TrustManager[] trustManagers = factory.getTrustManagers();
        X509TrustManager trustManager = (X509TrustManager) trustManagers[0];

        // 初始化sslContext
        SSLContext sslContext = SSLContext.getInstance("TLS"); // 这里SSL\TLS都可以
        sslContext.init(null, new TrustManager[] { trustManager }, null);

        // 获得sslSocketFactory
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

        // 初始化client builder
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        //关键步骤,在这里将HTTP/2协议添加进去
        List<Protocol> protocols = new ArrayList<>();
        protocols.add(Protocol.HTTP_1_1); // 这里如果,只指定h2的话会抛异常
        protocols.add(Protocol.HTTP_2); // 这里如果,只指定h2的话会抛异常
        builder.sslSocketFactory(sslSocketFactory, trustManager)
                .protocols(protocols) // 设置builder protocols
                .hostnameVerifier(new HostnameVerifier() { // 放过host验证
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });

        // build client
        client = builder.build();
    }
}

我们使用main方法测试:

    public static void main(String[] args) throws InterruptedException {
        Http2ClientUtil.doGetNoParams("/http2/visit");
    }

控制台打印:
基于Spring Boot2.0 & HTTP/2 实现服务器、客户端

至此,成功基于springboot & HTTP/2实现服务端、客户端。
感谢阅读!文章来源地址https://www.toymoban.com/news/detail-408468.html

到了这里,关于基于Spring Boot2.0 & HTTP/2 实现服务器、客户端的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于Netty实现一个HTTP服务器

    一、序言 Netty因其易编程,高可靠性,高性能的网络IO,在分布式开发中被广泛用于网络通信,比如RocketMQ,Dubbo底层都能看到Netty的身影,高性能的本质是其Reactor线程模型以及异步的编程处理。Reactor有三种模型,常用的有主从 Reactor多线程模式,具体表现如下: 在日常开发中

    2023年04月25日
    浏览(37)
  • 基于BaseHTTPRequestHandler的HTTP服务器基础实现

    BaseHTTPRequestHandler 是Python中的一个基类,属于 http.server 模块,用于处理HTTP请求的基本功能。它提供了处理常见HTTP请求方法(如GET、POST等)的默认实现,并允许你在子类中进行定制化扩展。下面详细介绍 BaseHTTPRequestHandler 的主要特点和使用方法: 主要特点: 处理HTTP请求:

    2024年02月08日
    浏览(34)
  • 基于C++的简单HTTP服务器实现

    基于C++的简单HTTP服务器实现 一个Web Server就是一个服务器软件(程序),或者是运行这个服务器软件的硬件(计算机)。其主要功能是通过HTTP协议与客户端(通常是浏览器(Browser))进行通信,来接收,存储,处理来自客户端的HTTP请求,并对其请求做出HTTP响应,返回给客户

    2024年02月02日
    浏览(34)
  • 基于 Python 实现一个简单的 HTTP 服务器

    文章这个题目,让我想起了大学时上《Unix 网络编程》这门专业课的家庭作业,题目几乎一模一样。 HTTP 服务器工作在服务端,主要功能包括处理来自客户端的请求,管理网络资源,以及生成和发送响应给客户端。在实际应用中,HTTP 服务器不仅限于传输 HTML 文档;它还可以传

    2024年03月22日
    浏览(40)
  • 从spring boot泄露到接管云服务器平台

    0x1前言 在打野的时候意外发现了一个站点存在springboot信息泄露,之前就有看到一些文章可以直接rce啥的,今天刚好试试。通过敏感信息发现存在accesskey泄露,就想直接通过解密,获取敏感信息,接管云平台。 首先说下这个漏洞的产生。主要是因为程序员开发时没有意识到暴

    2023年04月11日
    浏览(72)
  • Spring Boot 项目应用消息服务器RabbitMQ(简单介绍)

    本章讲述的是在用户下单环节,消息服务器RabbitMQ 的应用 在写一个电商项目的小demo,在电商项目中,消息服务器的应用: 1、订单状态通知:当用户下单、支付成功、订单发货、订单完成等关键节点时,可以通过消息服务器向用户发送相应的订单状态通知。 2、消息推送:通

    2024年02月13日
    浏览(57)
  • 【Java开发】 Spring 11 :Spring Boot 项目部署至云服务器

    Spring Boot 项目开发结束后的工作便是运维,简单来说需要配置 Web 运行参数和项目部署两大工作,本文将尽可能详细地给大家讲全! 目录 1 定制 Web 容器运行参数 1.1 运行参数介绍 1.2 项目搭建 ① 通过 IDEA Spring Initializr 创建项目 ② 添加 Spring Web 等依赖 ③ 编写 controller 层的

    2023年04月23日
    浏览(38)
  • 将Spring Boot项目打包部署到阿里云linux服务器

    首先 你要保证自己的服务器上有java环境 如果没有可以参考我的文章 linux服务器中安装java JDK1.8版本 然后 我们打开我们的Spring Boot项目 双击 package 生命周期进行打包 打包完成之后 我们找到 target 下面会有一个jar包 然后 我们右键它 如下图操作 系统就会帮你打开它所在的目录

    2024年02月16日
    浏览(41)
  • Spring Boot+Vue前后端分离项目如何部署到服务器

    🌟 前言 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 🤖 洛可可白 :个人主页 🔥 个人专栏 :✅前端技术 ✅后端技术 🏠 个人

    2024年04月11日
    浏览(36)
  • 解决Spring Boot 2.7.16 在服务器显示启动成功无法访问问题:从本地到服务器的部署坑

    🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐 🌊 《100天精通Golang(基础入门篇)》学会Golang语言

    2024年02月07日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包