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

如何使用Google Cloud Function记录下载日志并向客户端返回下载文件

Cloud Function中转GCS文件下载的配置方案

你的方案完全可行,只要正确配置响应头和处理流程,就能获得和直接访问GCS公开链接完全一致的下载体验,不需要修改用户侧的交互逻辑。

核心处理流程

  • 接收客户端传递的存储对象名称,先执行你需要的日志记录逻辑(可记录请求IP、User-Agent、请求时间、用户标识、对象名等自定义字段)
  • 从GCS存储桶中拉取对应对象的元数据和内容,优先透传GCS返回的原生响应头,仅必要时做自定义修改
  • 流式返回文件内容到客户端,避免大文件导致Cloud Function内存溢出

必须配置的响应头

以下响应头直接决定了下载体验是否和原链接一致,必须正确配置:

  • Content-Type:透传GCS中对应对象的contentType元数据,保证浏览器能正确识别文件类型,区分在线预览(如图片、PDF)和下载行为
  • Content-Disposition:优先透传GCS对象的原生配置,需要强制下载时设置为attachment; filename="自定义文件名.后缀",需要在线预览时设置为inline即可
  • Content-Length:透传GCS返回的对象大小,让浏览器可以正确显示下载进度,避免出现未知大小的下载提示
  • Cache-Control:透传GCS对象的缓存配置,避免重复下载浪费带宽
  • Access-Control-Allow-Origin:如果你的静态站点域名和Cloud Function域名不一致,需要配置为你的静态站点域名,避免跨域请求被拦截

如果需要支持大文件断点续传、多线程下载,还需要额外处理:

  • 读取请求头中的Range字段,向GCS请求对应范围的文件内容
  • 返回206 Partial Content状态码,同时设置Content-Range响应头,和GCS原生支持的范围请求行为保持一致

可选高性能方案

如果对传输性能要求较高,也可以在日志记录完成后返回302重定向到GCS的原公开链接,Cloud Function不需要处理文件传输,响应速度更快,体验完全一致。缺点是用户可以获取到GCS直链,后续直接访问直链的行为会绕过日志记录,可根据自身需求选择。

Node.js 环境示例代码

const {Storage} = require('@google-cloud/storage');
const storage = new Storage();
// 替换为你的存储桶名称
const GCS_BUCKET = 'your-bucket-name';

exports.recordAndServeFile = async (req, res) => {
  const targetObject = req.query.object_name;
  // 日志记录逻辑,可按需扩展字段
  console.log(JSON.stringify({
    time: new Date().toISOString(),
    client_ip: req.ip,
    user_agent: req.get('User-Agent'),
    requested_file: targetObject
  }));

  try {
    const file = storage.bucket(GCS_BUCKET).file(targetObject);
    const [meta] = await file.getMetadata();

    // 透传核心响应头
    res.set('Content-Type', meta.contentType);
    res.set('Content-Length', meta.size);
    res.set('Cache-Control', meta.cacheControl || 'public, max-age=86400');
    if (meta.contentDisposition) res.set('Content-Disposition', meta.contentDisposition);
    // 替换为你的静态站点域名,允许跨域访问
    res.set('Access-Control-Allow-Origin', 'https://your-static-site.com');

    // 流式返回文件,适配任意大小的文件
    file.createReadStream().pipe(res);
  } catch (e) {
    res.status(e.code === 404 ? 404 : 500).send(e.code === 404 ? 'File Not Found' : 'Server Error');
  }
};

内容的提问来源于stack exchange,提问作者John。

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 20:27:01