排查日志:http1.1 升级到 http2

问题背景

实习需求:把原有的系统从http1.1升级到http2

一开始觉得非常简单,思路大概就是:前端改配置升级、后端改配置升级、适配代理层nginx。

项目前后端配置:

image-20241022121711494

nginx配置:

image-20241022121853314

❗但是发送的请求在网页控制台发现还是http1.1🤔

逐步排查

1. 排查后端

写了个方法专门判断http版本

/**
* 测试请求是否为 http2
*/
@RestController
@RequestMapping("/apiTest")
public class HttpVersionController {

@GetMapping("/http-version")
public String getHttpVersion(HttpServletRequest request) {
System.out.println(request.getHeader("User-Agent"));
System.out.println(request.getRequestURL());
String protocol = request.getProtocol();

if ("HTTP/1.1".equals(protocol)) {
System.out.println(" HTTP/1.1");
return "This is an HTTP/1.1 request.";
} else if ("HTTP/2.0".equals(protocol)) {
System.out.println(" HTTP/2");
return "This is an HTTP/2 request.";
} else {
return "Unknown HTTP version: " + protocol;
}
}
}

直接访问后端接口返回的是http2,说明后端已经成功升级,不是后端的问题

image-20241022142941523

但是前端访问此接口返回的还是http1.1

image-20241022143627983

2. 排查nginx

在这个地方卡了很久,又是升级nginx又是make又是重新配置openssl又是配置tls,后面查看nginx的access.log发现这个系统根本没走nginx(流泪le家人们,这就是半路接手系统的弊端😭

3. 排查前端

那现在问题已经非常呼之欲出了!!就是前端的问题!!!🤯

使用echo | openssl s_client -alpn h2 -connect localhost:3100 | grep ALPN模拟向前端项目地址发送SSL握手,发现这个端口不支持ALPN,发送的请求有http2和http1.1,但最后选择了http1.1

image-20241022144724722

看起来解决办法就是让端口支持ALPN就可以了,也就是配置vite,但是我早在第一步就配置好了,在这里思考了非常久

之后搜索vite官网才发现上面写着:“启用 TLS + HTTP/2。注意:当 server.proxy 选项 也被使用时,将会仅使用 TLS。”

image-20241022141600185

自己测试了一下,确实是https属性和proxy属性只会有一个生效,而且优先生效proxy属性

如果注释proxy属性,开启https属性,发现端口就支持ALPN协议,且走的是http2;但是因为proxy失效,后端请求报错,如下图:

image-20241022143316300

所以最终原因就是使用的vite不支持server同时配置HTTP2和proxy,相关讨论:Support HTTP2 and Proxy at the same time? · Issue #4184 · vitejs/vite (github.com)

解决办法

  1. 使用相关插件支持http2和proxy,如williamyorkl/vite-plugin-proxy-middleware: a vite plugin that solve the conflict problem between turning on vite proxy and http2, you can use both http2 and proxy at the same time ;-) (github.com)
  2. 使用自定义的http2服务器

参考代码:

const fs = require('fs')
const http2 = require('http2')
const handler = require('vite').createServer({
// Vite server options
server: {
middlewareMode: 'html',
},
})

const server = http2.createSecureServer({
cert: fs.readFileSync('cert.pem'),
key: fs.readFileSync('key.pem'),
})

server.on('stream', (stream, headers) => {
handler.middlewares(stream, headers)
})

server.listen(3100, () => {
console.log('HTTP/2 server running on https://localhost:3100')
})

反思

  1. 感觉自己排查的思路还是有点慢,应该快一点反应过来不是后端的问题、不是nginx的问题,从而推出是前端的问题
  2. 这种问题不要老是想着问gpt,多去github上搜搜issus反而更合适,有时候经验比机器管用
  3. 每次都很容易被前端的bug困很久,找个时间去学学前端的进阶框架,起码得知道vite、webpack的用法等等

纪念我的2024.10.21,在图书馆改了一天这个东西🥺🥺🥺

image-20241022144250448