Node.js使用Redis处理gzip二进制数据解压失败求助
解决方案
问题根源是Node Redis v4+ 默认会将Buffer类型的存储值自动转换为UTF-8字符串,导致压缩后的二进制数据因编码转换被损坏,最终解压时触发*“无效头部”*错误。
修复方案
在存储和读取数据时,明确指定encoding: 'buffer'选项,强制Redis以原始二进制格式处理数据:
- 修改存储逻辑:
// 原代码 // await redis.set('gzip', compressed) // 修改后 await redis.set('gzip', compressed, { encoding: 'buffer' })
- 修改读取逻辑:
// 原代码 // const data = (await redis.get('gzip')) || Buffer.from('{}') // 修改后 const data = (await redis.get('gzip', { encoding: 'buffer' })) || Buffer.from('{}')
完整修复后的代码
import { promisify } from 'node:util' import { gzip } from 'node:zlib' import { gunzip } from 'node:zlib' import { redis } from '~/library/provider' const asyncGzip = promisify(gzip) const asyncGunzip = promisify(gunzip) export async function handler() { try { await redis.connect() } catch (/* c8 ignore next */ error) {} const compressed = await asyncGzip(Buffer.from(JSON.stringify({ ok: true }))) await redis.set('gzip', compressed, { encoding: 'buffer' }) // 新增编码选项 console.log('>>> compressed', compressed) const data = (await redis.get('gzip', { encoding: 'buffer' })) || Buffer.from('{}') // 新增编码选项 console.log('>>> data', data) const payload = await asyncGunzip(compressed) // OK! console.log('>>> payload', payload) const decompressed = await asyncGunzip(data) // 现在可以正常解压 console.log('>>> decompressed', decompressed.toString()) await redis.disconnect() return { statusCode: 200, body: JSON.stringify({ result: JSON.parse(decompressed.toString()) }), } }
原理说明
gzip压缩后的二进制数据包含大量非UTF-8兼容的字节,Node Redis v4默认的字符串序列化会将这些字节转换为UTF-8字符串,这个过程会丢失或篡改原始二进制信息。当从Redis读取并转回Buffer时,数据已经损坏,自然无法通过gzip的头部校验。指定encoding: 'buffer'后,Redis会直接存储和返回原始Buffer,避免任何编码转换,保证压缩数据的完整性。
内容的提问来源于stack exchange,提问作者Rodrigo
相关产品推荐
相关产品推荐

