当前位置: 首页 > news >正文

http1.x VS http2.x 协议

目录

http1.x & http2.x

关键区别

详解

总结

java代码样例

1. 添加依赖 (pom.xml)

2. 生成 SSL 证书 (测试用)

3. 配置文件 (application.yml)

4. 服务端主类

5. HTTP/2 服务配置类

6. 客户端 (Java 11+ HttpClient)

7. 运行步骤

8. 关键点说明


http1.x & http2.x

关键区别

HTTP/1.1 和 HTTP/2 是 Web 通信协议的两个主要版本,HTTP/2 旨在解决 HTTP/1.1 的许多性能限制,以提供更快的网页加载体验。下面是它们的主要区别:

特性

HTTP/1.1 (1997年至今)

HTTP/2 (2015年至今)

对性能和效率的影响

数据传输模型

基于文本的协议(可读性好)。

二进制分帧层协议(效率更高)。

二进制协议解析更快、更紧凑、更健壮。

连接复用

需要多个TCP连接(通常6-8个/域名)并行请求。
- 队头阻塞:同一连接上的请求必须按顺序响应。

单一持久连接 + 多路复用。
- 请求/响应被分解为帧,交错传输。
- 单个连接处理数百个并行流。

消除队头阻塞 → 减少延迟、提升并发能力。
减少TCP连接数 → 节省资源、提高效率。

头部压缩

冗余且未压缩。
- 每个请求发送完整头部(如Cookie、User-Agent等)。

使用HPACK压缩算法。
- 维护头部字段表,发送索引和哈夫曼编码值。

大幅减少头部开销(高达90%)→ 加快页面加载,对移动端友好。

服务器推送

无此功能。
- 客户端必须主动请求所有资源。

服务端可主动推送资源到客户端缓存。
- 在客户端请求前预知需要推送的资源(如CSS/JS)。

减少额外请求往返 → 提升页面渲染速度。需谨慎配置避免浪费带宽。

优先级

无显式优先级控制。
- 浏览器通过启发式规则(如将CSS/JS置于更高优先级)。

流可分配优先级和权重。
- 服务端据此优化资源传输顺序。

优化关键资源加载(如优先发送HTML/CSS)→ 提高感知性能。

安全加密

不强制HTTPS(可单独使用HTTP)。

虽未强制,但所有主流浏览器要求HTTPS(基于TLS)。

事实上的加密强制 → 提高安全性,但略微增加连接建立开销。

详解

  1. 二进制分帧层:
    ◦ HTTP/1.1:消息是纯文本格式(请求行、头部、正文)。人类可读,但解析效率低且易出错。◦ HTTP/2:在应用层(HTTP)和传输层(TCP)之间引入了一个二进制分帧层。HTTP消息(请求和响应)被分解为更小的、格式化的二进制帧(HEADERS帧、DATA帧等),然后发送。接收端再将帧重组为完整的消息。这使得解析更高效、更健壮,并为多路复用等特性奠定了基础。
  2. 多路复用:
    ◦ HTTP/1.1:
▪   队头阻塞:在单个TCP连接上,请求必须按发出顺序得到响应。如果一个请求处理缓慢(如大文件下载),后面的所有请求都会被阻塞,即使它们处理的资源已经准备好了。▪   连接数限制:浏览器为了解决队头阻塞和提升并行度,会为同一个域名打开多个TCP连接(通常是6-8个)。但这增加了服务器和网络资源消耗(内存、CPU、端口、慢启动、竞争带宽),并且在达到限制后仍可能排队。

◦ HTTP/2:

▪   单一连接:仅需一个TCP连接。▪   流与帧:HTTP/2引入了“流”的概念。每个请求/响应对在一个独立的流中进行。流被赋予唯一的ID。消息被拆分为帧后,不同流的帧可以在同一个TCP连接上交错发送和接收。▪   消除应用层队头阻塞:即使一个流的响应被延迟(如等待数据库查询),该阻塞只影响这一个流,其他流的帧可以继续传输。因此,慢响应不会阻塞整个连接。这大大提高了连接的利用率和并发效率。
  1. 头部压缩:
    ◦ HTTP/1.1:头部(包含 cookie、User-Agent、Accept-* 等字段)在每个请求中重复发送,且未经压缩。头部大小可能超过几百字节甚至几千字节,造成显著开销,尤其对大量小文件请求影响很大。◦ HTTP/2:使用 HPACK 压缩算法。它利用:
▪   静态哈夫曼编码:对头部字段值进行高效压缩。▪   维护客户端和服务端共享的头部字段表:常用的头部字段(如`:method: GET`, `:path: /index.html`)可以只发送一个索引号代替完整字符串。即使是动态变化的头部(如 Cookie),也通过记录之前的头部来避免重复发送。▪   这大大减少了头部开销(通常压缩率在 60%-90%),对降低延迟(尤其是高延迟网络)和提高带宽利用率非常有效。
  1. 服务器推送:
    ◦ HTTP/1.1:服务器只能被动响应客户端的请求。客户端必须解析 HTML,发现所需的资源(如 CSS、JS、图像),然后再发送新的请求去获取它们。这增加了额外的网络往返(RTT)。◦ HTTP/2:服务器可以在客户端明确请求之前,主动将资源“推送”给客户端。例如,当服务器收到对 index.html 的请求时,它可以立即把 styles.cssscript.js 一起推送过来(前提是服务器知道这些资源是后续渲染 index.html 所必需的)。客户端可以将这些推送的资源存储到缓存中。当它后续需要这些资源时,缓存中已经有了,节省了请求时间。推送是提前获取资源的一种方法。
  2. 流优先级:
    ◦ HTTP/1.1:浏览器会尝试猜测哪些资源(如 CSS, JS)更重要并优先请求它们,但协议本身没有提供优先级机制。◦ HTTP/2:允许客户端在发起请求时为流指定优先级和权重(依赖关系树)。服务器可以利用这些信息,优先处理和传输优先级高的流的帧(如关键 CSS),然后再传输低优先级的流(如图像)。这有助于优化内容的渲染顺序,提升用户体验(感知性能)。
  3. 加密要求:
    ◦ HTTP/1.1:可以在 HTTP(明文)或 HTTPS(HTTP over TLS)上运行。◦ HTTP/2:规范本身并不强制要求使用 TLS。然而,在实践当中,所有主要的浏览器都只支持在 HTTPS(TLS)上运行 HTTP/2。这意味着部署 HTTP/2 几乎必然同时启用了 HTTPS。这既提高了安全性,也简化了协议部署(避免了中间代理修改流量带来的问题)。

总结

• HTTP/1.1 是一个成熟的、广泛部署的基础协议,但它的文本格式、队头阻塞和缺乏压缩等问题限制了其性能。

• HTTP/2 通过引入二进制分帧、强制多路复用、高效头部压缩、服务器推送和优先级控制,从根本上解决了 HTTP/1.1 的性能瓶颈。它在单一连接上实现高效并行,显著减少了延迟,提高了网络带宽的利用率,从而大大加快了现代复杂网页的加载速度。同时,主流浏览器要求在 HTTPS 上使用 HTTP/2,也提升了整体安全性。

迁移建议: 对绝大多数现代网站,使用 HTTPS 并提供 HTTP/2 支持是推荐的性能和安全最佳实践。不过需要确保你的服务器和 CDN 已正确配置支持 HTTP/2。

java代码样例

下面是一个完整的 HTTP/2 实现示例,包含 Spring Boot 2.x 服务端和使用 Java HttpClient 的客户端:

服务端 (Spring Boot 2.7.x)

1. 添加依赖 (pom.xml)

<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.7.18</version></dependency><!-- HTTP/2 支持 --><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-core</artifactId><version>9.0.85</version></dependency><dependency><groupId>org.apache.tomcat</groupId><artifactId>tomcat-coyote</artifactId><version>9.0.85</version></dependency>
</dependencies>

2. 生成 SSL 证书 (测试用)

keytool -genkeypair -alias http2-demo -keyalg RSA -keysize 2048 \-storetype PKCS12 -keystore http2-demo.p12 -validity 3650
# 密码: changeit

3. 配置文件 (application.yml)

server:port: 8443ssl:key-store: classpath:http2-demo.p12key-store-password: changeitkey-store-type: PKCS12key-alias: http2-demohttp2:enabled: truetomcat:max-threads: 200

4. 服务端主类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@SpringBootApplication
public class Http2ServerApplication {public static void main(String[] args) {SpringApplication.run(Http2ServerApplication.class, args);System.out.println("HTTP/2 Server running on https://localhost:8443");}@RestControllerstatic class Http2Controller {@GetMapping("/")public String home() {return "Welcome to HTTP/2 Server!";}@GetMapping("/data")public String getData() {return "HTTP/2 Response: " + System.currentTimeMillis();}@GetMapping("/push-resource")public String getPushResource() {return "Pushed Resource Content";}@GetMapping("/stream")public Flux<String> getStream() {return Flux.interval(Duration.ofMillis(500)).map(tick -> "Stream data #" + tick + " @ " + Instant.now());}}
}

5. HTTP/2 服务配置类

import org.apache.coyote.http2.Http2Protocol;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class Http2Config {@Beanpublic WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {return factory -> factory.addConnectorCustomizers(connector -> {connector.addUpgradeProtocol(new Http2Protocol());});}
}

6. 客户端 (Java 11+ HttpClient)

  1. HTTP/2 客户端代码
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import javax.net.ssl.SSLContext;public class Http2Client {private static final String SERVER_URL = "https://localhost:8443/data";public static void main(String[] args) throws Exception {// 1. 演示HTTP/2请求singleRequest();// 2. 演示HTTP/2并发请求concurrentRequests();// 3. 演示HTTP/2服务端推送testServerPush();// 4. 演示HTTP/2流式响应streamResponse();}private static void singleRequest() throws Exception {HttpClient client = createHttpClient();HttpRequest request = HttpRequest.newBuilder().uri(URI.create(SERVER_URL)).GET().timeout(Duration.ofSeconds(10)).build();HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println("\n=== 单次请求结果 ===");printResponse(response);}private static void concurrentRequests() {HttpClient client = createHttpClient();List<CompletableFuture<Void>> futures = new ArrayList<>();System.out.println("\n=== 并发请求 (10次) ===");for (int i = 0; i < 10; i++) {final int requestId = i + 1;CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {try {HttpRequest request = HttpRequest.newBuilder().uri(URI.create(SERVER_URL + "?req=" + requestId)).GET().build();HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.printf("[%s] 请求 %d 完成: %s%n", response.version(), requestId, response.body());} catch (Exception e) {e.printStackTrace();}});futures.add(future);}// 等待所有请求完成CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();System.out.println("所有并发请求完成");}private static void testServerPush() throws Exception {HttpClient client = createHttpClient();HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://localhost:8443")).GET().build();// 处理服务端推送CompletableFuture<Void> pushFuture = client.sendAsync(request, HttpResponse.BodyHandlers.ofString(),// 推送处理器(initialRequest, pushRequest) -> {System.out.println("\n服务端推送资源: " + pushRequest.uri());return CompletableFuture.completedFuture(HttpResponse.BodyHandlers.ofString());}).thenApply(pushResponse -> {System.out.println("\n=== 服务端推送测试 ===");printResponse(pushResponse);return null;});pushFuture.join();}private static void streamResponse() throws Exception {HttpClient client = createHttpClient();HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://localhost:8443/stream")).GET().build();System.out.println("\n=== 流式响应 ===");client.sendAsync(request, HttpResponse.BodyHandlers.ofLines()).thenAccept(response -> {response.body().limit(5).forEach(line -> System.out.println("收到流数据: " + line));}).join();}private static HttpClient createHttpClient() {return HttpClient.newBuilder().version(HttpClient.Version.HTTP_2)  // 强制使用HTTP/2.sslContext(insecureContext())        // 忽略证书验证 (测试用).followRedirects(HttpClient.Redirect.NORMAL).build();}private static void printResponse(HttpResponse<?> response) {System.out.println("协议版本: " + response.version());System.out.println("状态码: " + response.statusCode());System.out.println("响应头: ");response.headers().map().forEach((k, v) -> System.out.println("  " + k + ": " + v));System.out.println("响应体: " + response.body());}// 创建不安全的SSL上下文 (仅用于测试!)private static SSLContext insecureContext() {try {java.security.KeyStore ks = java.security.KeyStore.getInstance("PKCS12");ks.load(null, null);javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("PKIX");tmf.init(ks);javax.net.ssl.TrustManager[] trustManagers = tmf.getTrustManagers();SSLContext sc = SSLContext.getInstance("TLS");sc.init(null, trustManagers, null);return sc;} catch (Exception e) {throw new RuntimeException("SSL上下文创建失败", e);}}
}

功能说明

服务端功能

  1. 基础端点:/, /data 返回简单响应
  2. 流式端点:/stream 返回服务器推送事件流
  3. 支持HTTP/2服务端推送
  4. 使用Tomcat HTTP/2实现

客户端功能

  1. singleRequest(): 发送单个HTTP/2请求
  2. concurrentRequests(): 发送10个并发请求(展示HTTP/2多路复用)
  3. testServerPush(): 接收服务端推送资源
  4. streamResponse(): 处理流式响应

7. 运行步骤

  1. 启动服务端
# 将生成的 http2-demo.p12 放入 resources 目录
mvn spring-boot:run
  1. 运行客户端
java Http2Client

预期输出

=== 单次请求结果 ===
协议版本: HTTP_2
状态码: 200
响应头: content-type: [text/plain;charset=UTF-8]date: [Thu, 01 Jan 2024 12:00:00 GMT]
响应体: HTTP/2 Response: 1700000000000=== 并发请求 (10次) ===
[HTTP_2] 请求 1 完成: HTTP/2 Response: 1700000000001
[HTTP_2] 请求 3 完成: HTTP/2 Response: 1700000000002
[HTTP_2] 请求 2 完成: HTTP/2 Response: 1700000000001
...
所有并发请求完成服务端推送资源: https://localhost:8443/push-resource=== 服务端推送测试 ===
协议版本: HTTP_2
状态码: 200
响应头: content-type: [text/plain;charset=UTF-8]
响应体: Welcome to HTTP/2 Server!=== 流式响应 ===
收到流数据: Stream data #0 @ 2024-01-01T12:00:00.123Z
收到流数据: Stream data #1 @ 2024-01-01T12:00:00.623Z
收到流数据: Stream data #2 @ 2024-01-01T12:00:01.123Z

8. 关键点说明

  1. 服务端配置
    • 使用 Tomcat 9+ 内置 HTTP/2 支持• 必须启用 SSL/TLS 加密• 添加 Http2Protocol 协议升级处理器
  2. 客户端特性
    • 使用 Java 11+ 的 HttpClient• 处理服务端推送 (pushPromiseHandler)• 接收流式响应 (BodyHandlers.ofLines())• 多路复用演示(10个并发请求共享单一连接)
  3. 安全注意
    • 生产环境应使用有效证书• insecureContext() 仅用于开发和测试• 正式环境应配置信任库和证书校验

此示例完整实现了 HTTP/2 的核心特性,包括二进制分帧、多路复用、服务端推送和流式响应,展示了与 HTTP/1.1 相比的性能优势。

相关文章:

  • csharp设计方法
  • Qt--信号槽发送QVector
  • 专注于PLC数据采集MES交互解决方案
  • Redis集群模式之Redis Cluster(3)
  • 【0.2 漫画操作系统原理】
  • 从0开始学习R语言--Day23--稳健回归
  • volka烹饪常用英语
  • Salesforce 推出Marketing Cloud Next营销云
  • Docker 部署 PostgreSQL 指南
  • 0x-5-ORA-03113-ORA-01081-记一次删归档改spfile-开实例
  • Vue3中v-bind指令用法详解
  • 论文略读: CITYANCHOR: CITY-SCALE 3D VISUAL GROUNDING WITH MULTI-MODALITY LLMS
  • 渲染进阶内容——机械动力的渲染(1)
  • 小程序跳转链接实战:https://wxaurl.cn/、weixin://dl/business/ 跳转与明文 URL Scheme 生成指南
  • MaxCompute的Logview分析详解
  • K8S 专栏 —— Pod 篇
  • 人工智能学习20-Pandas-自定义的函数
  • 单片机电路设计
  • 剖析电商搜索要点并基于Es+Redis模拟电商搜索行为
  • 滚珠螺杆的预紧间隙如何调整?
  • 加强网站及微信平台建设/银川网站seo
  • 坪山网站建设要多少钱/中囯联通腾迅
  • 360排名优化/seo综合查询是什么意思
  • 仙桃建设网站/关键词搜索爱站网
  • 那个平台的网页游戏好玩/baiduseoguide
  • 中国顶级网站建设/网络推广运营