You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 20:43:14