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

React客户端直接对接Google Cloud Storage实现文件上传下载求助

React客户端直接操作Google Cloud Storage(无服务端)方案

首先明确:绝对不能将GCP服务账号密钥(JSON文件)直接嵌入React客户端代码,这会导致密钥泄露,任何人都能获取你的GCP资源控制权,属于严重安全问题。以下是纯客户端的安全可行方案:

方案:通过Google Identity Services(OAuth 2.0)授权用户操作

该方案让用户用自己的Google账号授权,通过OAuth 2.0获取访问令牌,再调用GCS REST API完成上传/下载。

步骤1:GCP控制台配置OAuth客户端ID

  • 进入GCP控制台的「API和服务」→「凭据」页面
  • 创建「OAuth客户端ID」,应用类型选择「Web应用」
  • 在「已授权的JavaScript来源」中添加你的React应用域名(比如本地开发时填http://localhost:3000)
  • 保存后获取生成的客户端ID

步骤2:React代码实现

上传&下载文件示例

import { useEffect, useState } from 'react';

function GCSFileHandler() {
  const [accessToken, setAccessToken] = useState('');
  const [selectedFile, setSelectedFile] = useState(null);

  // 加载Google身份服务脚本
  useEffect(() => {
    const script = document.createElement('script');
    script.src = 'https://accounts.google.com/gsi/client';
    script.onload = initAuthClient;
    document.body.appendChild(script);

    return () => document.body.removeChild(script);
  }, []);

  // 初始化OAuth客户端
  const initAuthClient = () => {
    window.google.accounts.oauth2.initTokenClient({
      client_id: '你的OAuth客户端ID',
      scope: 'https://www.googleapis.com/auth/devstorage.read_write',
      callback: (tokenRes) => {
        if (tokenRes.access_token) setAccessToken(tokenRes.access_token);
      },
    });
  };

  // 触发用户授权
  const triggerAuth = () => {
    window.google.accounts.oauth2.getTokenClient().requestAccessToken({ prompt: 'consent' });
  };

  // 选择文件
  const handleFileSelect = (e) => {
    setSelectedFile(e.target.files[0]);
  };

  // 上传文件到GCS
  const uploadFile = async () => {
    if (!accessToken || !selectedFile) return;

    const bucketName = '你的存储桶名称';
    const uploadUrl = `https://storage.googleapis.com/upload/storage/v1/b/${bucketName}/o?uploadType=media&name=${selectedFile.name}`;

    try {
      const res = await fetch(uploadUrl, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': selectedFile.type,
        },
        body: selectedFile,
      });

      if (res.ok) {
        console.log('文件上传成功');
        // 可添加上传完成后的提示逻辑
      } else {
        const errData = await res.json();
        console.error('上传失败:', errData);
      }
    } catch (err) {
      console.error('请求异常:', err);
    }
  };

  // 从GCS下载文件
  const downloadFile = async (fileName) => {
    if (!accessToken) return;

    const bucketName = '你的存储桶名称';
    const downloadUrl = `https://storage.googleapis.com/storage/v1/b/${bucketName}/o/${encodeURIComponent(fileName)}?alt=media`;

    try {
      const res = await fetch(downloadUrl, {
        headers: { 'Authorization': `Bearer ${accessToken}` },
      });

      if (res.ok) {
        const blob = await res.blob();
        const downloadLink = document.createElement('a');
        downloadLink.href = window.URL.createObjectURL(blob);
        downloadLink.download = fileName;
        document.body.appendChild(downloadLink);
        downloadLink.click();
        window.URL.revokeObjectURL(downloadLink.href);
        document.body.removeChild(downloadLink);
      } else {
        const errData = await res.json();
        console.error('下载失败:', errData);
      }
    } catch (err) {
      console.error('请求异常:', err);
    }
  };

  return (
    <div>
      <button onClick={triggerAuth} disabled={!!accessToken}>
        授权Google账号
      </button>
      <input
        type="file"
        onChange={handleFileSelect}
        disabled={!accessToken}
        style={{ margin: '0 10px' }}
      />
      <button onClick={uploadFile} disabled={!accessToken || !selectedFile}>
        上传文件
      </button>
      <button onClick={() => downloadFile('目标文件名')} disabled={!accessToken} style={{ marginLeft: '10px' }}>
        下载示例文件
      </button>
    </div>
  );
}

export default GCSFileHandler;

关键注意事项

  • 权限配置:确保授权的Google账号在GCP IAM中拥有对应存储桶的权限(比如添加「Storage Object Creator」角色用于上传,「Storage Object Viewer」用于下载)
  • CORS设置:如果遇到跨域错误,需要在GCP控制台给存储桶配置CORS规则,允许你的React应用域名发起请求。示例CORS规则:
    [
      {
        "origin": ["http://localhost:3000"],
        "method": ["GET", "POST", "PUT"],
        "responseHeader": ["Authorization", "Content-Type"],
        "maxAgeSeconds": 3600
      }
    ]
    
  • 令牌有效期:OAuth访问令牌有有效期(默认约1小时),可以通过refresh_token实现自动刷新,避免用户重复授权。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:33:21