请求网站响应回的文本带有乱码,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-Encoding
和Accept-Encoding
在一起协商。
Accept-Encoding
设置在请求头当中,会告诉服务器,我可以接受哪种编码压缩。
Content-Encoding
设置在响应头中,会告诉客户端,我用的是哪种编码压缩。
他们俩个算是一个协商的作用。
比如说:
客户端发送请求带有表明我可以接受gzip
、deflate
两种压缩方式,
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
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 > *