通过Google Cloud Function上传文件至GCS后文件为空问题排查
问题描述
我尝试通过Google Cloud Function处理HTTP POST请求的文件上传,并将文件存储到Google Cloud Storage存储桶中。文件看似上传成功,控制台显示正确的文件大小,但查看时文件损坏,下载后文件大小为0字节。
我的Google Cloud Function代码如下:
const packageObj = require('./package.json'); const functions = require('@google-cloud/functions-framework'); const { Storage } = require('@google-cloud/storage'); const storage = new Storage(); functions.http('main', (req, res) => { res.set('Access-Control-Allow-Origin', '*'); if (req.method === 'OPTIONS') { res.set('Access-Control-Allow-Methods', 'GET'); res.set('Access-Control-Allow-Headers', 'Content-Type'); res.set('Access-Control-Max-Age', '3600'); res.status(204).send(''); } else if (req.method === 'POST') { const file = req.body; const bucketName = 'MY_BUCKET_NAME'; const bucket = storage.bucket(bucketName); const f = storage.bucket(bucketName).file('test.jpg'); f.save(file).then(() => { res.set('Content-Type', 'application/json'); res.status(200).send(JSON.stringify( { version: packageObj.version, message: 'File uploaded!' }, null, 2 )); }); } });
我使用functions-framework,运行命令:
functions-framework --target=main
然后执行:
curl -F 'data=@test/resources/car_image.jpg' http://localhost:8080/main
(我也部署了函数进行测试,排除functions-framework的问题,但结果相同。)
在控制台中,文件大小显示为62.9KB,与我上传的测试图片大小一致,但下载后文件大小为0字节,且预览损坏。
解决方案
问题根源及修复点如下:
- 未解析multipart表单数据:
curl -F发送的是multipart/form-data格式,直接读取req.body无法获取正确的文件二进制内容,需用multer中间件处理。 - CORS配置错误:OPTIONS请求中允许的方法仅为
GET,但实际使用POST,需修正允许的请求方法。 - 文件保存对象错误:直接保存
req.body会存储解析后的表单对象,而非文件二进制数据。
步骤1:安装依赖
npm install multer
步骤2:修改函数代码
const packageObj = require('./package.json'); const functions = require('@google-cloud/functions-framework'); const { Storage } = require('@google-cloud/storage'); const multer = require('multer'); const storage = new Storage(); // 配置multer使用内存存储,临时保存文件缓冲区 const upload = multer({ storage: multer.memoryStorage() }); // 用multer中间件解析名为'data'的表单字段(对应curl中的字段名) functions.http('main', upload.single('data'), (req, res) => { res.set('Access-Control-Allow-Origin', '*'); if (req.method === 'OPTIONS') { // 修正CORS配置,允许POST和OPTIONS方法 res.set('Access-Control-Allow-Methods', 'POST, OPTIONS'); res.set('Access-Control-Allow-Headers', 'Content-Type'); res.set('Access-Control-Max-Age', '3600'); return res.status(204).send(''); } if (req.method !== 'POST') { return res.status(405).send('Method Not Allowed'); } // 校验文件是否存在 if (!req.file) { return res.status(400).json({ error: 'No file uploaded' }); } const bucketName = 'MY_BUCKET_NAME'; const file = storage.bucket(bucketName).file('test.jpg'); // 上传文件缓冲区到GCS,同时指定文件类型 file.save(req.file.buffer, { contentType: req.file.mimetype, resumable: false }) .then(() => { res.set('Content-Type', 'application/json'); res.status(200).json({ version: packageObj.version, message: 'File uploaded!' }); }) .catch(err => { console.error('Upload error:', err); res.status(500).json({ error: 'File upload failed' }); }); });
内容的提问来源于stack exchange,提问作者antun
相关产品推荐
相关产品推荐

