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
相关产品推荐
相关产品推荐

