Node.js中https与zlib解析StackOverflow的gzip响应失败
解决Node.js中zlib.gunzip报"incorrect header check"的问题
问题出在你处理响应数据的方式上:你把二进制的gzip数据当成字符串拼接了。
当你执行data += chunk时,Node.js会把Buffer类型的chunk自动转成UTF-8字符串,但gzip是二进制格式,转字符串的过程会破坏原始字节结构——有些二进制字节无法被UTF-8正确编码,会被替换成占位符或丢失,导致最终的data已经不是完整的gzip数据,解压时自然会触发头部校验错误。
修复方案1:用Buffer数组收集并合并数据
直接用数组存储每个Buffer块,最后用Buffer.concat()合并成完整的二进制Buffer,再传给zlib.gunzip:
const https = require('https') const zlib = require('zlib') const options = { headers: { 'Accept-Encoding': 'gzip' }, } https.get('https://stackoverflow.com/', options, resp => { const chunks = []; resp.on("data", chunk => { chunks.push(chunk); // 直接存Buffer,不转字符串 }); resp.on("end", () => { if (resp.headers['content-encoding'] !== 'gzip') { console.log('should get gzip') process.exit(1) } console.log('got gzip!') const buffer = Buffer.concat(chunks); zlib.gunzip(buffer, (err, unzippedData) => { if (err) { console.error(err); return; } console.log(unzippedData.toString()); // 转成字符串查看内容 }); }); })
修复方案2:用管道流处理(更推荐)
Node.js的流API可以直接把响应流和zlib解压流对接,自动处理数据传输,无需手动收集chunk,内存效率更高:
const https = require('https') const zlib = require('zlib') const options = { headers: { 'Accept-Encoding': 'gzip' }, } https.get('https://stackoverflow.com/', options, resp => { if (resp.headers['content-encoding'] !== 'gzip') { console.log('should get gzip') process.exit(1) } console.log('got gzip!') // 把响应流通过管道传给gunzip流,再输出到控制台 resp.pipe(zlib.createGunzip()).pipe(process.stdout); })
管道流的优势在于它是流式处理,不需要把整个响应数据加载到内存里,尤其适合处理大体积的响应内容。
内容的提问来源于stack exchange,提问作者Mathieu Paturel
相关产品推荐
相关产品推荐

