使用原生Rust发送HTTP GET请求无响应的原因是什么?
解决Rust TCP流发送HTTP请求后无法收到响应的问题
你的代码发送请求后一直卡住,核心原因是HTTP/1.1默认启用持久连接(Keep-Alive)——服务器返回响应后不会立刻关闭TCP连接,而read_to_string会一直阻塞等待流关闭,自然无法拿到完整响应。
下面给你几种实用的解决思路:
方法1:添加Connection: close请求头
直接告诉服务器:"返回响应后就关闭连接",这样read_to_string就能读到响应结尾并正常返回:
use std::io::{Read, Result, Write}; use std::net::TcpStream; fn main() { if let Err(err) = connect() { println!("err = {}", err); } } fn connect() -> Result<()> { let mut stream = TcpStream::connect("www.google.de:80")?; let mut request_data = String::new(); request_data.push_str("GET / HTTP/1.1"); request_data.push_str("\r\n"); request_data.push_str("Host: www.google.de"); request_data.push_str("\r\n"); // 新增这行,通知服务器关闭连接 request_data.push_str("Connection: close"); request_data.push_str("\r\n"); request_data.push_str("\r\n"); println!("request_data = {:?}", request_data); stream.write_all(request_data.as_bytes())?; let mut buf = String::new(); let result = stream.read_to_string(&mut buf)?; println!("读取到字节数 = {}", result); println!("响应内容:\n{}", buf); Ok(()) }
方法2:使用成熟的HTTP客户端库(推荐)
手动处理TCP流和HTTP协议细节很容易踩坑,实际项目里更推荐用reqwest这类专门的HTTP库,它会帮你自动处理连接管理、响应解析等问题:
首先在Cargo.toml中添加依赖:
[dependencies] reqwest = { version = "0.11", features = ["blocking"] }
然后简化代码:
fn main() { if let Err(err) = connect() { println!("err = {}", err); } } fn connect() -> Result<(), reqwest::Error> { let response = reqwest::blocking::get("http://www.google.de")?; println!("响应状态码: {}", response.status()); let body = response.text()?; println!("响应内容:\n{}", body); Ok(()) }
方法3:手动解析Content-Length读取响应
如果想深入学习HTTP协议细节,可以自己解析响应头中的Content-Length字段,然后读取指定长度的字节,避免依赖read_to_string的阻塞行为:
use std::io::{BufRead, BufReader, Read, Result, Write}; use std::net::TcpStream; fn main() { if let Err(err) = connect() { println!("err = {}", err); } } fn connect() -> Result<()> { let mut stream = TcpStream::connect("www.google.de:80")?; let request_data = "GET / HTTP/1.1\r\nHost: www.google.de\r\n\r\n"; stream.write_all(request_data.as_bytes())?; let mut reader = BufReader::new(stream); let mut headers = String::new(); // 读取响应头,直到遇到空行(头和体的分隔符) reader.read_line(&mut headers)?; while !headers.ends_with("\r\n\r\n") { let mut line = String::new(); reader.read_line(&mut line)?; headers.push_str(&line); } // 从响应头中解析Content-Length let content_length: usize = headers .lines() .find(|line| line.starts_with("Content-Length:")) .and_then(|line| line.split_whitespace().nth(1)) .and_then(|s| s.parse().ok()) .expect("无法获取Content-Length字段"); // 读取指定长度的响应体 let mut body = vec![0; content_length]; reader.read_exact(&mut body)?; let body_str = String::from_utf8_lossy(&body); println!("响应头:\n{}", headers); println!("响应体:\n{}", body_str); Ok(()) }
这种方式适合学习HTTP协议底层逻辑,但日常开发还是优先用现成库更高效。
内容的提问来源于stack exchange,提问作者RSX
相关产品推荐
相关产品推荐

