为什么来自 api.color.pizza 的 reqwest 响应返回意外的字节?

Sru*_*nde 2 http rust reqwest

我正在尝试解析来自 GET 请求的响应,但输出似乎是随机字节。

此问题仅在我尝试此网站 ( https://api.color.pizza/v1/123123 )时发生,并且在尝试其他网站时响应符合预期。

在浏览器中测试,我知道正确的响应,并且在比较正确响应的字节(存储在变量中k)和来自 reqwest 的响应时,字节完全不同。

重现错误的代码如下:

fn main() -> Result<(), Box<dyn std::error::Error>> {
    //Expected output
    let k = r##"{"colors":[{"hex":"#123120","name":"Méi H?i Coal","rgb":{"r":18,"g":49,"b":32},"requestedHex":"#123123","luminance":29.48870965301805,"distance":3}]}"##;

    let request_url = "https://api.color.pizza/v1/123123";
    let resp = reqwest::blocking::get(request_url)?.text()?;

    println!("{}", resp);

    let r1 = resp.into_bytes();
    let r2 = String::from(k).into_bytes();
    assert_eq!(&r1[..], &r2[..]);

    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

输出是:

fn main() -> Result<(), Box<dyn std::error::Error>> {
    //Expected output
    let k = r##"{"colors":[{"hex":"#123120","name":"Méi H?i Coal","rgb":{"r":18,"g":49,"b":32},"requestedHex":"#123123","luminance":29.48870965301805,"distance":3}]}"##;

    let request_url = "https://api.color.pizza/v1/123123";
    let resp = reqwest::blocking::get(request_url)?.text()?;

    println!("{}", resp);

    let r1 = resp.into_bytes();
    let r2 = String::from(k).into_bytes();
    assert_eq!(&r1[..], &r2[..]);

    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

mca*_*ton 6

https://color.pizza 上的服务器总是压缩输出,即使客户端没有要求它。

你可以看到这个:

$ curl -i 'https://api.color.pizza/v1/123123' 
HTTP/1.1 200 OK
Server: Cowboy
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: false
Access-Control-Max-Age: 86400
Access-Control-Allow-Headers: X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Date: Wed, 06 May 2020 19:04:47 GMT
Transfer-Encoding: chunked
Via: 1.1 vegur

Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: <FILE>" to save to a file.
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,你需要启用gzipreqwest

fn main() -> Result<(), Box<dyn std::error::Error>> {
    //Expected output
    let k = r##"{"colors":[{"hex":"#123120","name":"Méi H?i Coal","rgb":{"r":18,"g":49,"b":32},"requestedHex":"#123123","luminance":29.48870965301805,"distance":3}]}"##;

    let request_url = "https://api.color.pizza/v1/123123";
    let resp = reqwest::blocking::ClientBuilder::new()
        .gzip(true)
        .build()?
        .get(request_url)
        .send()?
        .text()?;

    println!("{}", resp);

    let r1 = resp.into_bytes();
    let r2 = String::from(k).into_bytes();
    assert_eq!(&r1[..], &r2[..]);

    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

这需要以下gzip功能:

[dependencies]
reqwest = { version = "*", features = ["blocking", "gzip"] }
Run Code Online (Sandbox Code Playgroud)