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

React应用调用GCS下载文件报错:readable is not async iterable

问题根源

直接在React前端使用@google-cloud/storage库是错误的——这个库是为Node.js环境设计的,依赖Node.js特有的API(比如文件系统fs、流stream等),浏览器环境不支持这些API,这就是你遇到TypeError: readable is not async iterable报错的核心原因。另外,把服务账号密钥直接写在前端代码里会导致密钥泄露,带来严重的安全风险。

解决方案

推荐两种安全可行的方案:

方案1:通过后端代理获取文件内容

编写一个Node.js后端接口(比如Google Cloud Functions),在后端用@google-cloud/storage读取GCS文件内容,再返回给前端,前端通过fetch调用该接口获取数据。

后端示例代码(Cloud Functions)

const {Storage} = require('@google-cloud/storage');
const storage = new Storage();

exports.getGcsFile = async (req, res) => {
  const bucketName = 'my-bucket.appspot.com';
  const fileName = 'my-file.csv';
  
  try {
    const [contents] = await storage.bucket(bucketName).file(fileName).download();
    res.status(200).send(contents.toString());
  } catch (err) {
    console.error('文件下载失败:', err);
    res.status(500).send('获取文件内容失败');
  }
};

前端修改后代码

import React, {useState, useEffect} from 'react';

export default function TestsLight() {
    const [fileData, setFileData] = useState(null);

    useEffect(() => {
        fetch('/api/getGcsFile')
            .then(res => res.text())
            .then(data => setFileData(data))
            .catch(err => console.error('请求错误:', err));
    }, []);

    return (
        <div>
            {fileData ? fileData : <span>no data</span>}
        </div>
    )
}

方案2:使用预签名URL(Signed URLs)

在后端生成一个带有效期的预签名URL,这个URL允许临时访问指定的GCS文件,前端拿到URL后直接用fetch下载内容。

后端生成预签名URL示例代码

const {Storage} = require('@google-cloud/storage');
const storage = new Storage();

exports.getSignedUrl = async (req, res) => {
  const bucketName = 'my-bucket.appspot.com';
  const fileName = 'my-file.csv';
  const options = {
    version: 'v4',
    action: 'read',
    expires: Date.now() + 15 * 60 * 1000, // 设置15分钟有效期
  };

  try {
    const [url] = await storage.bucket(bucketName).file(fileName).getSignedUrl(options);
    res.status(200).send({url});
  } catch (err) {
    console.error('生成预签名URL失败:', err);
    res.status(500).send('生成访问链接失败');
  }
};

前端修改后代码

import React, {useState, useEffect} from 'react';

export default function TestsLight() {
    const [fileData, setFileData] = useState(null);

    useEffect(() => {
        // 先获取预签名URL
        fetch('/api/getSignedUrl')
            .then(res => res.json())
            .then(({url}) => fetch(url))
            .then(res => res.text())
            .then(data => setFileData(data))
            .catch(err => console.error('请求错误:', err));
    }, []);

    return (
        <div>
            {fileData ? fileData : <span>no data</span>}
        </div>
    )
}
额外注意事项
  • 绝对不要在前端代码中暴露服务账号密钥,否则任何人都能获取密钥并控制你的GCS存储桶及其他Google Cloud资源。
  • 预签名URL要设置合理的有效期,避免长期有效带来的安全风险。
  • 若文件较大,建议使用流式下载或分段下载,避免内存占用过高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:50:46