如何使用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。
相关产品推荐
相关产品推荐

