You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:58:00