使用 Hyper 和 Flate2 读取 gzip 响应

Read gzip response with Hyper and Flate2

Hyper 具有函数 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> 将 HTTP 响应的内容读入所提供的 &mut [u8]

Flate2 可以 gunzip:

let mut d = GzDecoder::new("...".as_bytes()).unwrap();
let mut s = String::new();
d.read_to_string(&mut s).unwrap();
println!("{}", s);

我试着把这两件事放在一起:

fn gunzip(r: &Response) -> String {
    let mut zs: &mut [u8] = &mut[];
    r.read(zs);
    let mut d = GzDecoder::new(zs).unwrap();
    let mut s = String::new();
    d.read_to_string(&mut s).unwrap();
    s
}

我收到错误:

error[E0277]: the trait bound `[u8]: std::io::Read` is not satisfied
   --> tests/integration.rs:232:21
    |
232 |         let mut d = GzDecoder::new(zs).unwrap();
    |                     ^^^^^^^^^^^^^^ trait `[u8]: std::io::Read` not satisfied
    |
    = help: the following implementations were found:
    = help:   <&'a [u8] as std::io::Read>
    = note: required because of the requirements on the impl of `std::io::Read` for `&mut [u8]`
    = note: required by `<flate2::read::DecoderReader<R>>::new`

我哪里错了?


编辑:最终的工作解决方案:

fn gunzip(r: &mut Response) -> String {
    let mut buffer = Vec::new();
    let _ = r.read_to_end(&mut buffer).unwrap();
    let mut d = GzDecoder::new(buffer.as_slice()).unwrap();
    let mut s = String::new();
    d.read_to_string(&mut s).unwrap();
    s
}

GzDecoder::new 的参数是用泛型类型定义的,因此 Rust 不会执行某些需要固定类型时会发生的转换。

您可以通过取消引用可变切片然后引用结果来将可变切片转换为不可变切片。

let mut d = GzDecoder::new(&*zs).unwrap();

这是不使用另一个缓冲区的另一种方法:

extern crate hyper;
extern crate flate2;

use std::io::Read;

use hyper::client::Client;
use hyper::header::{Headers, AcceptEncoding, Encoding, qitem};

use flate2::read::GzDecoder;

fn main() {
    let c = Client::new();

    let mut req = c.get("http://httpbin.org/gzip");
    let mut headers = Headers::new();
    headers.set(
        AcceptEncoding(vec![qitem(Encoding::Gzip)])
    );
    req = req.headers(headers);

    let res = req.send().unwrap();
    let mut decoder = GzDecoder::new(res).unwrap();
    let mut buf = String::new();

    let _ = decoder.read_to_string(&mut buf);
    println!("{}", buf);
}

此示例使用来自 HTTPBIN 的 gzip 端点来测试 Response 可以在 GzDecoder.

中使用

我的 Cargo 文件中使用的依赖项:

[dependencies]
hyper = "0.9"
flate2 = "0.2"

P.S。 unwrap() 调用是为了简洁起见:)