Node.js应用与Google Cloud Storage Bucket认证异常:无法下载文件
问题原因及解决方案
问题核心原因
- 你代码里用的
mediaLink是Google Cloud Storage的原生对象链接,这个链接必须携带身份认证信息才能访问,但你的Bucket关闭了公共访问权限,前端/客户端直接访问该链接属于匿名请求,会被细粒度ACL拦截,因此抛出权限不足的错误。 - 上传和文件列表功能正常,是因为这两个操作由后端通过拥有Storage Admin权限的服务账号完成,已经完成了身份认证;但下载时你直接让客户端请求
mediaLink,跳过了后端的认证环节,变成了匿名访问,自然无法通过权限校验。
修复方案
方案1:生成签名URL(推荐)
签名URL会给链接附加临时访问权限,允许客户端在指定有效期内直接访问对象,无需后端转发。修改代码如下:
调整getListFiles函数:
const getListFiles = async (req, res) => { try { const [files] = await bucket.getFiles(); let fileInfos = []; for (const file of files) { // 生成有效期1小时的可读签名URL(可按需调整时长) const signedUrl = await file.getSignedUrl({ action: 'read', expires: '1h' }); fileInfos.push({ name: file.name, url: signedUrl[0] // 替换为签名后的可访问URL }); } res.status(200).send(fileInfos); } catch (err) { console.log(err); res.status(500).send({ message: "Unable to read list of files!" }); } };
调整download函数:
const download = async (req, res) => { try { const file = bucket.file(req.params.name); // 生成有效期15分钟的下载签名URL const signedUrl = await file.getSignedUrl({ action: 'read', expires: '15m' }); res.redirect(signedUrl[0]); } catch (err) { res.status(500).send({ message: "Could not download the file. " + err }); } };
方案2:后端转发文件内容
如果不想用签名URL,可以让后端先读取文件内容,再将内容返回给客户端,全程由后端完成身份认证:
const download = async (req, res) => { try { const file = bucket.file(req.params.name); // 获取文件元数据,设置响应头 const [metadata] = await file.getMetadata(); res.set('Content-Type', metadata.contentType); res.set('Content-Disposition', `attachment; filename="${metadata.name}"`); // 管道传输文件内容到响应 file.createReadStream().pipe(res); } catch (err) { res.status(500).send({ message: "Could not download the file. " + err }); } };
内容的提问来源于stack exchange,提问作者alphatango165
相关产品推荐
相关产品推荐

