GCS解压转码仅返回单行内容的问题排查求助
GCS解压转码仅返回单行内容的问题排查求助
我最近碰到一个GCS的诡异问题:把gzip压缩的JSON文件上传到GCS存储桶后,设置了Content-Encoding: gzip和Content-Type: application/json元数据——按照GCS文档,这样应该支持自动解压转码。但下载时,响应虽然是解压后的内容,却只返回第一行数据,可我上传的明明是多行的完整文件。
补充几个关键细节:
- 我用Bun的S3原生API和
gzipSync处理上传流程 - 如果不设置
Content-Encoding: gzip,自己本地解压文件的话,内容是完整的 - 压缩时直接调用了Bun的
gzipSync,没有指定任何额外参数
我怀疑问题要么出在GCP的转码逻辑,要么是我压缩文件的方式不对。下面是我用的上传代码:
static async writeStreamToBucket<T>( data: T[], fileName: string, bucketName: string, projectID?: string, hook: (data: T) => string = JSON.stringify, compress = false, isPublic = false, withLog = true ): Promise<void> { const storage = new Storage({ projectId: projectID ?? getGoogleProjectID() }); const bucket = storage.bucket(bucketName); const gcsfile = bucket.file(fileName); const gcsClient = new S3Client({ accessKeyId: process.env.GCS_ACCESS_ID, secretAccessKey: process.env.GCS_SECRET, endpoint: "https://storage.googleapis.com", bucket: bucketName, }); const file = gcsClient.file(fileName); const exist = await file.exists(); if (exist) await file.delete(); const stream = file.writer({ type: "application/json" }); if (compress) for (const d of data) await stream.write(gzipSync(`${hook(d)}\n`)); else { const encoder = new TextEncoder(); for (const d of data) await stream.write(encoder.encode(`${hook(d)}\n`)); } await stream.end(); await gcsfile.setMetadata({ cacheControl: "public, max-age=300", contentEncoding: compress ? "gzip" : undefined, contentType: "application/json", }); if (isPublic) await gcsfile.makePublic(); withLog && log.info(`✅ successfully updated https://storage.cloud.google.com/${bucketName}/${fileName}`); }
后来我盯着代码看了半天,突然意识到可能的问题:我是逐行调用gzipSync压缩,再把这些独立的压缩块写入流,而不是先把所有行拼接成完整文本再整体压缩。gzip格式确实允许包含多个独立压缩块,但GCS的解压转码逻辑可能只识别并处理第一个块,所以只返回了第一行数据。
如果是这个原因,解决方案应该是调整压缩逻辑:先拼接所有内容,再一次性压缩,比如把代码里的压缩部分改成这样:
if (compress) { // 先拼接所有行内容,再整体压缩 const fullContent = data.map(d => `${hook(d)}\n`).join(''); await stream.write(gzipSync(fullContent)); } else { // 原有的非压缩逻辑保持不变 const encoder = new TextEncoder(); for (const d of data) await stream.write(encoder.encode(`${hook(d)}\n`)); }
不过我还不能100%确定就是这个原因,有没有碰到过类似问题的朋友?或者还有其他可以排查的方向吗?
备注:内容来源于stack exchange,提问作者Alexandre Schaffner
相关产品推荐
相关产品推荐

