为什么这个请求中,reqwest没有返回内容的长度?

3
我不明白为什么以下使用reqwest函数的代码没有返回任何内容:
  fn try_get() {
      let wc = reqwest::Client::new();
      wc.get("https://httpbin.org/json").send().map(|res| {
          println!("{:?}", res);
          println!("length {:?}", res.content_length());
      });
  }

我期望这个函数会显示响应对象并给我内容长度。它做了第一个但没有做第二个:
Response { url: "https://httpbin.org/json", status: 200, headers: {"access-control-allow-credentials": "true", "access-control-allow-origin": "*", "connection": "keep-alive", "content-type": "application/json", "date": "Tue, 26 Feb 2019 00:52:47 GMT", "server": "nginx"} }
length None

这很令人困惑,因为我使用cURL命中相同的端点时,它会按预期返回主体:
$ curl -i https://httpbin.org/json
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 26 Feb 2019 00:54:57 GMT
Server: nginx
Content-Length: 429
Connection: keep-alive

{
  "slideshow": {
    "author": "Yours Truly",
    "date": "date of publication",
    "slides": [
      {
        "title": "Wake up to WonderWidgets!",
        "type": "all"
      },
      {
        "items": [
          "Why <em>WonderWidgets</em> are great",
          "Who <em>buys</em> WonderWidgets"
        ],
        "title": "Overview",
        "type": "all"
      }
    ],
    "title": "Sample Slide Show"
  }
}

我的函数有什么问题,为什么它没有提供内容长度?
1个回答

4
reqwest文档中的content_length()方法是一个很好的起点。它说明:

获取响应的内容长度(如果已知)。

可能未知的原因:

  • 服务器没有发送内容长度头部。
  • 响应被压缩并自动解码(从而更改了实际解码长度)。

通过查看您的示例curl输出,其中包含Content-Length: 429,因此第一种情况已经涵盖。现在让我们尝试禁用gzip:

let client = reqwest::Client::builder()
  .gzip(false)
  .build()
  .unwrap();

client.get("https://httpbin.org/json").send().map(|res| {
  println!("{:?}", res);
  println!("length {:?}", res.content_length());
});

记录哪些日志

length Some(429)

所以第二种情况是问题。默认情况下,reqwest 似乎自动处理gzip压缩的内容,而 curl 则不会。

Content-Length HTTP 头是完全可选的,因此通常依赖其存在会是一个错误。您应该使用其他 reqwest API 读取请求中的数据,然后计算数据本身的长度。例如,您可以使用.text()方法。

let wc = reqwest::Client::new();
let mut response = wc.get("https://httpbin.org/json").send().unwrap();
let text = response.text().unwrap();

println!("text: {} => {}", text.len(), text);

同样地,对于二进制数据,您可以使用 .copy_to():

let wc = reqwest::Client::new();
let mut response = wc.get("https://httpbin.org/json").send().unwrap();

let mut data = vec![];
response.copy_to(&mut data).unwrap();

println!("data: {}", data.len());

谢谢。在这种情况下,我该如何确定内容的实际长度并分配缓冲区以读取它? - user8370684
最好使用.text(),并直接使用返回的String,而不是尝试在某处预分配缓冲区。 Content-Length不是请求中必需的标头,因此依赖它是错误的。 - loganfsmyth
是的,但我的一些查询不是文本而是二进制。 text 可以吗?如果不行,我认为我仍然需要使用缓冲区读取它。 - user8370684
我在我的回答中添加了更多的例子。 - loganfsmyth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接