请求网站响应回的文本带有乱码,Content-encoding:gzip

今天写爬虫请求网站后,返回的数据中有乱码,怎么转都转不了。

后来研究了一番,应该是Content-encoding惹的祸:

废话少说:

  • 先说解决方案,然后再说原理

一、解决方案:

第一种:

把请求头Accept-Encoding去掉

//map.put("Accept-Encoding", "gzip, deflate");

但是可能返回的数据还有乱码,那我们就可以用Java字符串的方式来处理:

String result = new String(responseBody.getBytes("ISO-8859-1"),"UTF-8");

第二种:

找到对应的解压算法,将字符串解压:

因为我爬取的网站响应头中Content-Encoding:的属性值为gzip,所以我就用gzip的解压算法来解压

/**
     * GZIP解压字符串
     * 解决Content-Encoding: gzip 的问题
     * @param str 源字符串
     * @return
     * @throws IOException
     */
public static String uncompressString(String str) throws IOException {
    if (str == null || str.length() == 0) {
        return str;
    }
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ByteArrayInputStream in = new ByteArrayInputStream(str
                                                       .getBytes("ISO-8859-1"));
    GZIPInputStream gunzip = new GZIPInputStream(in);
    byte[] buffer = new byte[256];
    int n;
    while ((n = gunzip.read(buffer)) >= 0) {
        out.write(buffer, 0, n);
    }
    return out.toString();
}

二、原理

Content-EncodingAccept-Encoding在一起协商。

Accept-Encoding设置在请求头当中,会告诉服务器,我可以接受哪种编码压缩。

Content-Encoding设置在响应头中,会告诉客户端,我用的是哪种编码压缩。

他们俩个算是一个协商的作用。

比如说:

客户端发送请求带有表明我可以接受gzipdeflate两种压缩方式,

Accept-Encoding: gzip, deflate

服务器在 Content-Encoding 响应首部提供了实际采用的压缩模式:

Content-Encoding: gzip

PS: 服务器端并不强制要求一定使用何种压缩模式。采用哪种压缩方式高度依赖于服务器端的设置,及其所采用的模块。

Content-Encoding

引用一个MDN上的话:

Content-Encoding 是一个实体消息首部,用于对特定媒体类型的数据进行压缩。当这个首部出现的时候,它的值表示消息主体进行了何种方式的内容编码转换。这个消息首部用来告知客户端应该怎样解码才能获取在 Content-Type 中标示的媒体类型内容。

一般建议对数据尽可能地进行压缩,因此才有了这个消息首部的出现。不过对于特定类型的文件来说,比如jpeg图片文件,已经是进行过压缩的了。有时候再次进行额外的压缩无助于负载体积的减小,反而有可能会使其增大。

翻译为人话就是说:

Content-Encoding就是对数据进行了编码压缩,从而起到了压缩数据的作用。

  • 优点: 大大提高了传输的效率。

目前有以下五种形式:

Content-Encoding: gzip
Content-Encoding: compress
Content-Encoding: deflate
Content-Encoding: identity
Content-Encoding: br

每一种形式就对应这一种压缩算法。

Content-Encoding: gzip

  • 表示采用 Lempel-Ziv coding (LZ77) 压缩算法,以及32位CRC校验的编码方式。这个编码方式最初由 UNIX 平台上的 gzip 程序采用。出于兼容性的考虑, HTTP/1.1 标准提议支持这种编码方式的服务器应该识别作为别名的 x-gzip指令。

Content-Encoding: compress

  • 采用 Lempel-Ziv-Welch (LZW) 压缩算法。这个名称来自UNIX系统的 compress 程序,该程序实现了前述算法。与其同名程序已经在大部分UNIX发行版中消失一样,这种内容编码方式已经被大部分浏览器弃用,部分因为专利问题(这项专利在2003年到期)。

Content-Encoding: deflate

  • 采用 zlib 结构 (在 RFC 1950 中规定),和 deflate 压缩算法(在 RFC 1951 中规定)。

Content-Encoding: identity

  • 用于指代自身(例如:未经过压缩和修改)。除非特别指明,这个标记始终可以被接受。

Content-Encoding: br

  • 表示采用 Brotli 算法的编码方式。

Accept-Encoding

HTTP 请求头 Accept-Encoding 会将客户端能够理解的内容编码方式——通常是某种压缩算法——进行通知(给服务端)。通过内容协商的方式,服务端会选择一个客户端提议的方式,使用并在响应头 Content-Encoding 中通知客户端该选择。

几种形式:

Accept-Encoding: gzip
Accept-Encoding: compress
Accept-Encoding: deflate
Accept-Encoding: br
Accept-Encoding: identity
Accept-Encoding: *

其中有些指令在Content-Encoding已经说过了,就不在赘述。说一下上边没说过的:

*

  • 匹配其他任意未在该请求头字段中列出的编码方式。假如该请求头字段不存在的话,这个值是默认值。它并不代表任意算法都支持,而仅仅表示算法之间无优先次序。

;q=

  • 值代表几种算法的优先级,又称为权重。

例如:

Accept-Encoding: gzip

Accept-Encoding: gzip, compress, br

Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1
// 表示几种压缩算法的优先级,br > gzip > *

更多推荐

请求网站响应的文本带有乱码,原来是Content-encoding惹的祸,一文带你搞懂`Content-encoding`、`Accept-Encoding`