如何从hyper::client::请求中正确读取字节序列并将其作为UTF-8字符串打印到控制台?

如何从hyper::client::请求中正确读取字节序列并将其作为UTF-8字符串打印到控制台?,utf-8,rust,bytebuffer,Utf 8,Rust,Bytebuffer,我正在探索Rust,并尝试发出一个简单的HTTP请求(使用hyper-crate)并将响应正文打印到控制台。响应实现std::io::Read。通过阅读各种文档源和基本教程,我获得了以下代码,我使用RUST\u BACKTRACE=1 cargo run编译并执行这些代码: use hyper::client::Client; use std::io::Read; pub fn print_html(url: &str) { let client = Client::new()

我正在探索Rust,并尝试发出一个简单的HTTP请求(使用hyper-crate)并将响应正文打印到控制台。响应实现
std::io::Read
。通过阅读各种文档源和基本教程,我获得了以下代码,我使用
RUST\u BACKTRACE=1 cargo run编译并执行这些代码:

use hyper::client::Client;
use std::io::Read;

pub fn print_html(url: &str) {
    let client = Client::new();
    let req = client.get(url).send();

    match req {
        Ok(mut res) => {
            println!("{}", res.status);

            let mut body = String::new();

            match res.read_to_string(&mut body) {
                Ok(body) => println!("{:?}", body),
                Err(why) => panic!("String conversion failure: {:?}", why)
            }
        },
        Err(why) => panic!("{:?}", why)
    }
}
预期: HTTP服务器提供的一个漂亮的、人类可读的HTML正文内容被打印到控制台

实际:
200正常
线程“”在“字符串转换失败:错误{repr:Custom(Custom{kind:InvalidData,错误:StringError(“流未包含有效的UTF-8”)}”)时崩溃,src/printer.rs:16
堆栈回溯:
1:0x109e1faeb-std::sys::backtrace::tracing::imp::write::H3800F45F42104B8
2:0x109e21565-std::panicking::default_hook:7b$$u7b$closure$u7d$$u7d$::h0ef6c8db532f55dc
3:0x109e2119e-std::panicking::default_hook::hf3839060ccbb8764
4:0x109e177f7-标准::恐慌::带钩的生锈恐慌::h5dd7da6bb3d06020
5:0x109e21b26-标准::恐慌::开始恐慌::h9bf160aee246b9f6
6:0x109e18248-标准::恐慌::开始恐慌fmt::haf08a9a70a097ee1
7:0x109d54378-libplayder::printer::print_html::hff00c339aa28fde4
8:0x109d53d76-游乐场::主要::h0b7387c23270ba52
9:0x109e20d8d-std::恐慌::尝试::呼叫::hbbf4746cba890ca7
10:0x109e23fcb-试运行
11:0x109e23f65-\u生锈\u可能会\u引起恐慌\u
12:0x109e20bb1-std::rt::lang_start::hbcefdc316c2fbd45
13:0x109d53da9-主
错误:进程未成功退出:`target/debug/playway`(退出代码:101)
思想 由于我从服务器收到了
200ok
,我相信我已经收到了来自服务器的有效响应(我也可以通过使用更熟悉的编程语言执行相同的请求来经验证明这一点)。因此,该错误一定是由于我错误地将字节序列转换为UTF-8字符串引起的

选择 我还尝试了以下解决方案,这使我能够将字节作为一系列十六进制字符串打印到控制台,但我知道这根本是错误的,因为UTF-8字符可以有1-4个字节。因此,在本例中,尝试将单个字节转换为UTF-8字符只适用于非常有限(确切地说是255)的UTF-8字符子集

use hyper::client::Client;
use std::io::Read;

pub fn print_html(url: &str) {
    let client = Client::new();
    let req = client.get(url).send();

    match req {
        Ok(res) => {
            println!("{}", res.status);

            for byte in res.bytes() {
                print!("{:x}", byte.unwrap());
            }
        },
        Err(why) => panic!("{:?}", why)
    }
}

我们可以使用
iconv
命令确认从
http://www.google.com
是无效的UTF-8:

$wgethttp://google.com -O page.html
$iconv-f utf-8 page.html>/dev/null
iconv:位置5591处的非法输入序列
对于其他一些URL(如
http://www.reddit.com
)代码工作正常

如果我们假设大部分数据是有效的UTF-8,我们可以使用以下方法来解决问题:

pub fn print_html(url: &str) {
    let client = Client::new();
    let req = client.get(url).send();

    match req {
        Ok(mut res) => {
            println!("{}", res.status);

            let mut body = Vec::new();

            match res.read_to_end(&mut body) {
                Ok(_) => println!("{:?}", String::from_utf8_lossy(&*body)),
                Err(why) => panic!("String conversion failure: {:?}", why),
            }
        }
        Err(why) => panic!("{:?}", why),
    }
}

请注意,然后返回
Ok
,返回的是成功时读取的字节数,而不是读取的数据。

如果您实际查看Google返回的标题:

HTTP/1.1200正常
日期:2016年7月22日星期五20:45:54 GMT
过期:-1
缓存控制:专用,最大年龄=0
内容类型:text/html;字符集=ISO-8859-1
P3P:CP=“这不是P3P策略!请参阅https://www.google.com/support/accounts/answer/151657?hl=en 有关详细信息,请参阅。“
服务器:gws
X-XSS-Protection:1;模式=块
X-Frame-Options:SAMEORIGIN
设置Cookie:NID=82=YwAD4Rj09u6gUA8OtQH73BUz6UlNdeRc9Z_iGjyaDqFdRGMdslypu1zsSDWQ4xRJFyEn9-UtR7U6G7HKehoyxvy9HItnDlg8iLsxzlhNcg01luW3_3L9S3DMHIVH;expires=2017年1月21日星期六20:45:54 GMT;路径=/;domain=.google.ca;HttpOnly
备选议定书:443:quic
Alt Svc:quic=“:443”;ma=2592000;v=“36,35,34,33,32,31,30,29,28,27,26,25”
接受范围:无
改变:接受编码
传输编码:分块
你可以看到

内容类型:text/htmlcharset=ISO-8859-1

另外

因此,该错误一定是由于我错误地将字节序列转换为UTF-8字符串引起的

没有发生到UTF-8的转换<代码>读取字符串
只需确保数据为UTF-8

简单地说,假设任意HTML页面以UTF-8编码是完全错误的。充其量,您必须解析头以找到编码,然后转换数据。这很复杂,因为


找到正确的编码后,如果结果是偶数文本,可以使用板条箱(如)将结果正确转换为UTF-8!请记住,HTTP可以返回二进制文件,如图像。

您能给出生成此错误的url吗?
http://www.google.com
。糟糕的谷歌!我想一定是codez。下次我会记得尝试多个站点,它确实对其他站点有效。谢谢同时也感谢关于返回值的注释。