当使用curl时如何正确处理gzipped页面?

184

我写了一个bash脚本,使用curl从网站获取输出并在html输出上进行一系列的字符串操作。问题是当我对返回其输出为gzipped的网站运行它时,会出现问题。在浏览器中访问该网站没有问题。

当我手动运行curl时,我得到了gzipped输出:

$ curl "http://example.com"

以下是来自该网站的标题:

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=utf-8
X-Powered-By: PHP/5.2.17
Last-Modified: Sat, 03 Dec 2011 00:07:57 GMT
ETag: "6c38e1154f32dbd9ba211db8ad189b27"
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Cache-Control: must-revalidate
Content-Encoding: gzip
Content-Length: 7796
Date: Sat, 03 Dec 2011 00:46:22 GMT
X-Varnish: 1509870407 1509810501
Age: 504
Via: 1.1 varnish
Connection: keep-alive
X-Cache-Svr: p2137050.pubip.peer1.net
X-Cache: HIT
X-Cache-Hits: 425

我知道返回的数据是经过gzip压缩的,因为这个返回的是HTML,正如预期的那样:

$ curl "http://example.com" | gunzip

我不想通过gunzip来管道输出,因为该脚本在其他站点上按原样工作,而通过gzip进行管道传输会破坏该功能。

我的尝试

  1. 更改用户代理(我尝试了与浏览器发送的相同字符串“Mozilla/4.0”等)
  2. man curl
  3. 谷歌搜索
  4. 在stackoverflow上搜索

所有的都没有结果

有什么想法吗?


1
对我来说,问题在于cURL无法解压Brotli(curl 7.54.0(x86_64-apple-darwin17.0)libcurl/7.54.0 LibreSSL/2.0.20 zlib/1.2.11 nghttp2/1.24.0)-通过从Accept-Encoding中删除br来解决它。请参见https://dev59.com/tmMk5IYBdhLWcg3wxAry。 - The Onin
行为已经被改变。尝试单独使用 curl -sSv https://stackoverflow.com/ |&rg -i'gzip|accept',和 --compressed一起使用。除非 curl 通过 Accept-Encoding,否则服务器不会对响应进行gzip压缩。 - x-yuri
2个回答

350

curl会自动解压响应,如果你设置了--compressed标志:

curl --compressed "http://example.com"

--compressed (HTTP)请求使用libcurl支持的算法之一获取压缩的响应,并保存未经压缩的文档。如果使用此选项且服务器发送不受支持的编码,则curl将报告错误。

gzip很可能被支持,但您可以通过运行curl -V并查找“Features”行中的libz来进行检查:

$ curl -V
...
Protocols: ...
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz 
请注意,实际上是网站本身有问题。如果curl没有传递Accept-Encoding: gzip请求头,则服务器不应发送压缩响应。

33
这似乎是一个Curl的bug,因为它应该根据响应来触发解码,而不是根据请求(考虑到它支持gzip)。引用HTTP 1.1:“如果请求中没有Accept-Encoding字段,则服务器可以假定客户端将接受任何内容编码。”但随后它确实说,在那种情况下,服务器不应该对内容进行编码。 - George Lund
6
这也设置了请求头:"Accept-Encoding: deflate, gzip"。这很好,因为如果服务器提供gzip和非gzip,你只需要使用"--compressed"而不需要自己添加接受编码头。 - mbert
令人惊讶的是,设置 Accept-Encoding: deflate, gzip 是不够的 - 即使服务器返回带有 Content-Encoding: gzip 的gzip响应,curl也不会自动解压缩它。需要使用 --compressed 标志。 - rjh
将以下与程序相关的内容从英语翻译成中文。仅返回已翻译的文本:(如果有--raw,请删除)。 - jonincanada
有趣的是,man页面上说,“标头不会被修改。”尽管它们显然被修改了。 - x-yuri
显示剩余3条评论

1
在相关的错误报告当服务器返回gzip数据时,未使用--compressed参数导致原始压缩输出 #2836中,开发人员表示:

服务器不应该在客户端没有明确表明接受gzip编码时发送content-encoding: gzip。

此外,当您在curl中不使用--compressed参数时,您告诉命令行工具您更喜欢存储精确流(无论是否压缩)。我在这里看不到curl的错误...

所以,如果服务器可能发送gzipped内容,请使用--compressed让curl自动解压缩它。


这并不总是合理或可能的。如果你不拥有的服务器配置不正确,你很难让他们修复它。编写防御性代码是解决这个问题的好方法。请参见George Lund的评论以获取另一个原因,为什么“一切都已经坏了”。™。 - BryanH
1
我不想和他产生矛盾,因为我认为他非常了解HTTP,但是......“服务器不应该在没有客户端发出可接受信号的情况下发送内容编码:gzip。”问题是,通过省略“Accept-Encoding”标头,curl确实发出了可接受的信号。标准规定,在这种情况下,“如果请求中没有Accept-Encoding字段,则用户代理将考虑任何内容编码都是可接受的。”(要发出不接受编码的信号,我认为需要使用Accept-Encoding:identity*; q = 0,或空标头。) - Thanatos

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