我正在学习在 Rust 中使用 HTTP/3,但是当我在浏览器中打开 https://127.0.0.1:4433 时,我不断收到此错误。
错误无法访问此站点,127.0.0.1 拒绝连接
编译器没有错误。是因为证书的原因吗?问题是我也没有 SSL 证书,我当前使用的证书是使用 OpenSSL 自签名的。有谁拥有有效的 SSL 证书,请尝试运行我的代码以查看它是否有效,这样我就可以确定问题是否与证书有关,因为编译器中没有错误消息。我已在防火墙上激活 TCP 和 UDP 端口 4433。有谁知道为什么会发生这种情况?这是我的代码。
Cargo.toml:
[package]
name = "http3"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0"
bytes = "1"
futures = "0.3"
h3 = { version = "*", features = ["tracing"] }
h3-quinn = { version = "*", features = ["tracing"] }
h3-webtransport = { version = "*" }
http = "1"
quinn = { version = "0.11", default-features = false, features = [
"runtime-tokio",
"rustls",
"ring",
] }
rcgen = { version = "0.13" }
rustls = { version = "0.23", default-features = false, features = [
"logging",
"ring",
"std",
] }
rustls-native-certs = "0.7"
structopt = "0.3"
tokio = { version = "1.27", features = ["full"] }
tracing = "0.1.37"
tracing-subscriber = { version = "0.3", default-features = false, features = [
"fmt",
"ansi",
"env-filter",
"time",
"tracing-log",
] }
octets = "0.3.0"
tracing-tree = { version = "0.3" }
rustls-pemfile = "2.0"
主要.rs :
use std::{net::SocketAddr, path::PathBuf, sync::Arc};
use bytes::Bytes;
use http::{Request, Response, StatusCode};
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use structopt::StructOpt;
use tokio::{fs::File, io::AsyncReadExt};
use tracing::{error, info, trace_span};
use h3::{error::ErrorLevel, quic::BidiStream, server::RequestStream};
use h3_quinn::quinn::{self, crypto::rustls::QuicServerConfig};
#[derive(StructOpt, Debug)]
#[structopt(name = "server")]
struct Opt {
#[structopt(
name = "dir",
short,
long,
help = "Root directory of the files to serve. \
If omitted, server will respond OK."
)]
pub root: Option<PathBuf>,
#[structopt(
short,
long,
default_value = "127.0.0.1:4433",
help = "What address:port to listen for new connections"
)]
pub listen: SocketAddr,
#[structopt(flatten)]
pub certs: Certs,
}
#[derive(StructOpt, Debug)]
pub struct Certs {
#[structopt(
long,
short,
default_value = "cert.pem",
help = "Certificate for TLS in PEM format. If present, `--key` is mandatory."
)]
pub cert: PathBuf,
#[structopt(
long,
short,
default_value = "key.pem",
help = "Private key for the certificate in PEM format."
)]
pub key: PathBuf,
}
static ALPN: &[u8] = b"h3";
fn load_pem_cert(path: PathBuf) -> Result<Vec<CertificateDer<'static>>, Box<dyn std::error::Error>> {
let cert_file = std::fs::File::open(path)?;
let mut reader = std::io::BufReader::new(cert_file);
let certs = rustls_pemfile::certs(&mut reader)
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.map(CertificateDer::from)
.collect();
Ok(certs)
}
fn load_pem_key(path: PathBuf) -> Result<PrivateKeyDer<'static>, Box<dyn std::error::Error>> {
let key_file = std::fs::File::open(path.clone())?;
let mut reader = std::io::BufReader::new(key_file);
let pkcs8_keys = rustls_pemfile::pkcs8_private_keys(&mut reader)
.collect::<Result<Vec<_>, _>>()?;
if let Some(key) = pkcs8_keys.into_iter().next() {
return Ok(PrivateKeyDer::from(key));
}
let key_file = std::fs::File::open(path)?;
let mut reader = std::io::BufReader::new(key_file);
let rsa_keys = rustls_pemfile::rsa_private_keys(&mut reader)
.collect::<Result<Vec<_>, _>>()?;
if let Some(key) = rsa_keys.into_iter().next() {
return Ok(PrivateKeyDer::from(key));
}
Err("No valid private key found in PEM file".into())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)
.with_writer(std::io::stderr)
.with_max_level(tracing::Level::INFO)
.init();
let opt = Opt::from_args();
let root = if let Some(root) = opt.root {
if !root.is_dir() {
return Err(format!("{}: is not a readable directory", root.display()).into());
} else {
info!("serving {}", root.display());
Arc::new(Some(root))
}
} else {
Arc::new(None)
};
let Certs { cert, key } = opt.certs;
let certs = load_pem_cert(cert)?;
let key = load_pem_key(key)?;
let mut tls_config = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, key)?;
tls_config.max_early_data_size = u32::MAX;
tls_config.alpn_protocols = vec![ALPN.into()];
let mut server_config =
quinn::ServerConfig::with_crypto(Arc::new(QuicServerConfig::try_from(tls_config)?));
let transport_config = Arc::get_mut(&mut server_config.transport).unwrap();
transport_config.keep_alive_interval(Some(std::time::Duration::from_secs(5)));
let endpoint = quinn::Endpoint::server(server_config, opt.listen)?;
info!("listening on {}", opt.listen);
while let Some(new_conn) = endpoint.accept().await {
trace_span!("New connection being attempted");
let root = root.clone();
tokio::spawn(async move {
match new_conn.await {
Ok(conn) => {
info!("new connection established from {:?}", conn.remote_address());
let mut h3_conn = h3::server::Connection::new(h3_quinn::Connection::new(conn))
.await
.unwrap();
loop {
match h3_conn.accept().await {
Ok(Some((req, stream))) => {
info!("new request: {:#?}", req);
let root = root.clone();
tokio::spawn(async {
if let Err(e) = handle_request(req, stream, root).await {
error!("handling request failed: {}", e);
}
});
}
Ok(None) => break,
Err(err) => {
error!("error on accept {}", err);
match err.get_error_level() {
ErrorLevel::ConnectionError => break,
ErrorLevel::StreamError => continue,
}
}
}
}
}
Err(err) => {
error!("accepting connection failed: {:?}", err);
}
}
});
}
endpoint.wait_idle().await;
Ok(())
}
async fn handle_request<T>(
req: Request<()>,
mut stream: RequestStream<T, Bytes>,
serve_root: Arc<Option<PathBuf>>,
) -> Result<(), Box<dyn std::error::Error>>
where
T: BidiStream<Bytes>,
{
let mut contents = Vec::new();
println!("hello dari http 3");
match req.uri().path() {
"/" => {
contents.extend_from_slice(b"Welcome to the root page!");
}
"/api/hello" => {
let json_response = b"{\"message\": \"Hello from API!\"}";
contents.extend_from_slice(json_response);
stream.send_response(
Response::builder()
.status(StatusCode::OK)
.header("content-type", "application/json")
.body(())
.unwrap(),
).await?;
}
path if path.starts_with("/static/") => {
if let Some(root) = serve_root.as_ref() {
let file_path = root.join(&path[8..]);
let mut file = File::open(&file_path).await?;
file.read_to_end(&mut contents).await?;
} else {
contents.extend_from_slice(b"No static file root set.");
}
}
_ => {
contents.extend_from_slice(b"404 Not Found");
stream.send_response(
Response::builder()
.status(StatusCode::NOT_FOUND)
.header("content-type", "text/plain")
.body(())
.unwrap(),
).await?;
}
}
let contents = Bytes::from(contents);
stream.send_data(contents).await?;
stream.finish().await?;
Ok(())
}
您面临的问题至少之一是缺乏 HTTP/3 服务发现。 TLS ALPN 不够,因为导航到
https://127.0.0.1:4433
的浏览器将首先建立 TCP 连接。您应该考虑在 TCP 端口 4433 上托管 TCP、HTTP/1.1 和/或 HTTP/2 服务器,为每个响应添加 Alt-Svc: h3=":4433"; ma=3600
标头。除此之外,TCP 服务器应该返回相同的响应。
您可以在这里阅读更多内容:https://my.f5.com/manage/s/article/K16240003
如果您只需要以编程方式连接到您的服务器,则可以绕过上述需要;只是不要指望浏览器能够连接。