Rust Hyper 0.14无TLS的HTTP2后端无法运行问题咨询
解决Hyper 0.14无TLS下HTTP2服务无法工作的问题
问题原因
Hyper 0.14中直接使用Server::builder(incoming).http2_only(true)配置无TLS的HTTP2服务会失效,核心原因是:
- 明文传输场景下的HTTP2依赖h2c协议,客户端需要么直接发送HTTP2的PRI帧(即"Prior Knowledge"模式),要么通过HTTP1.1的
Upgrade头完成协议升级。 - 仅设置
http2_only(true)的服务端不会处理Upgrade升级逻辑,普通客户端(默认配置的curl、浏览器)会发送HTTP1.1请求,直接被服务端拒绝。
解决方案
要实现无TLS的HTTP2服务,需兼容h2c的两种连接方式:处理HTTP1.1到HTTP2的升级请求,同时支持客户端直接用Prior Knowledge模式连接。以下是完整实现代码:
完整示例代码
use hyper::{Body, Request, Response, Server}; use hyper::service::{make_service_fn, service_fn}; use hyper::server::conn::Http; use hyper::upgrade::Upgraded; use std::convert::Infallible; use tokio::net::TcpListener; // 处理升级后的HTTP2连接 async fn handle_upgraded_conn(upgraded: Upgraded) { if let Err(e) = Http::new() .http2_only(true) .serve_connection(upgraded, service_fn(handle_request)) .await { eprintln!("升级连接处理失败: {}", e); } } // 核心请求处理逻辑 async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible> { Ok(Response::new(Body::from("Hello HTTP/2 (明文h2c)!"))) } #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let addr = ([127, 0, 0, 1], 3000).into(); let listener = TcpListener::bind(addr).await?; // 创建服务工厂,处理连接和升级请求 let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(|req: Request<Body>| async move { // 检查是否存在h2c升级请求 if let Some(upgrade) = req.headers().get(hyper::header::UPGRADE) { if upgrade == "h2c" { match req.into_parts().1.upgrade().await { Ok(upgraded) => { // 异步处理升级后的HTTP2连接 tokio::spawn(handle_upgraded_conn(upgraded)); // 返回切换协议响应 Ok(Response::builder() .status(hyper::StatusCode::SWITCHING_PROTOCOLS) .header(hyper::header::UPGRADE, "h2c") .header(hyper::header::CONNECTION, "Upgrade") .body(Body::empty()) .unwrap()) } Err(e) => { eprintln!("升级失败: {}", e); Ok(Response::new(Body::from("升级失败"))) } } } else { handle_request(req).await } } else { // 客户端不支持升级时,返回HTTP1.1响应或自定义内容 handle_request(req).await } })) }); let server = Server::builder(listener).serve(make_svc); println!("服务启动,监听地址: http://{}", addr); server.await?; Ok(()) }
测试方式
使用支持h2c的客户端验证:
- 用curl的Prior Knowledge模式直接连接:
curl --http2-prior-knowledge http://localhost:3000 - 或者发送带
Upgrade: h2c和Connection: Upgrade头的HTTP1.1请求,触发协议升级。
关键说明
- 若要强制仅支持HTTP2,必须同时兼容Prior Knowledge直接连接和HTTP1.1升级两种h2c连接方式。
- Hyper的
Http::serve_connection方法可单独处理每个连接的协议逻辑,是实现h2c升级的核心工具。
内容的提问来源于stack exchange,提问作者RTX Gaming
相关产品推荐
相关产品推荐

