Rob*_*ann 3 bytebuffer utf-8 rust
我正在探索 Rust 并尝试发出一个简单的 HTTP 请求(使用 hyper crate)并将响应正文打印到控制台。响应实现std::io::Read. 阅读各种文档来源和基本教程,我得到了以下代码,我使用以下代码编译和执行RUST_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)
}
}
Run Code Online (Sandbox Code Playgroud)
由 HTTP 服务器传送的正文的一个漂亮的、人类可读的 HTML 内容被打印到控制台。
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)
}
}
Run Code Online (Sandbox Code Playgroud)
自从我200 OK从服务器收到后,我相信我收到了来自服务器的有效响应(我也可以通过使用更熟悉的编程语言执行相同的请求来凭经验证明这一点)。因此,该错误一定是我错误地将字节序列转换为 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)
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以通过iconv命令确认返回的数据http://www.google.com不是有效的 UTF-8:
$ wget http://google.com -O page.html
$ iconv -f utf-8 page.html > /dev/null
iconv: illegal input sequence at position 5591
Run Code Online (Sandbox Code Playgroud)
对于其他一些网址(如http://www.reddit.com),代码工作正常。
如果我们假设大部分数据是有效的 UTF-8,我们可以使用String::from_utf8_lossy来解决这个问题:
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),
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,Read::read_to_string并在成功时Read::read_to_end 返回Ok读取字节数,而不是读取数据。
如果您实际查看 Google 返回的标头:
HTTP/1.1 200 OK
Date: Fri, 22 Jul 2016 20:45:54 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: NID=82=YwAD4Rj09u6gUA8OtQH73BUz6UlNdeRc9Z_iGjyaDqFdRGMdslypu1zsSDWQ4xRJFyEn9-UtR7U6G7HKehoyxvy9HItnDlg8iLsxzlhNcg01luW3_-HWs3l9S3dmHIVh; expires=Sat, 21-Jan-2017 20:45:54 GMT; path=/; domain=.google.ca; HttpOnly
Alternate-Protocol: 443:quic
Alt-Svc: quic=":443"; ma=2592000; v="36,35,34,33,32,31,30,29,28,27,26,25"
Accept-Ranges: none
Vary: Accept-Encoding
Transfer-Encoding: chunked
Run Code Online (Sandbox Code Playgroud)
你可以看到
内容类型:文本/html;字符集=ISO-8859-1
此外
因此,该错误一定是我错误地将字节序列转换为 UTF-8 字符串引起的。
有没有转换为UTF-8发生。read_to_string只是确保数据是UTF-8。
简而言之,假设任意 HTML 页面以 UTF-8 编码是完全不正确的。充其量,您必须解析标头以找到编码,然后转换数据。这很复杂,因为没有真正定义标头在.
找到正确的编码后,您可以使用诸如encoding 之类的 crate将结果正确转换为 UTF-8,如果结果甚至是文本!请记住,HTTP 可以返回二进制文件,例如图像。
| 归档时间: |
|
| 查看次数: |
1341 次 |
| 最近记录: |