Vite+React上传图片至Firebase遇CORS错误及Bucket查找问题
解决Firebase Storage上传时的CORS错误
问题概述
调用uploadBytes函数时触发CORS错误,注释该函数后其他功能正常:
Access to XMLHttpRequest at [firebase storage api url] from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
已定位到需要更新Firebase Storage Bucket的CORS策略,但执行gsutil cors set cors.json gs://<你的应用名称>.appspot.com时找不到对应的Bucket。
相关代码文件
vite.config.js
import { resolve } from 'path'; import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' const root = resolve(__dirname, 'src'); const outDir = resolve(__dirname, 'dist'); // https://vitejs.dev/config/ export default defineConfig({ root, plugins: [react()], build: { outDir, emptyOutDir: true, rollupOptions: { input: { main: resolve(root, "index.html"), login: resolve(root, 'auth', "login.html"), } } } })
firebase.js
// Import the functions you need from the SDKs you need import { initializeApp } from "firebase/app"; import { getAnalytics } from "firebase/analytics"; import { getAuth } from "firebase/auth"; import { getFirestore } from "firebase/firestore"; // TODO: Add SDKs for Firebase products that you want to use // Your web app's Firebase configuration // For Firebase JS SDK v7.20.0 and later, measurementId is optional const firebaseConfig = { apiKey: import.meta.env.VITE_PUBLIC_API_KEY, authDomain: import.meta.env.VITE_PUBLIC_AUTH_DOMAIN, projectId: import.meta.env.VITE_PUBLIC_PROJECT_ID, storageBucket: import.meta.env.VITE_PUBLIC_STORAGE_BUCKET, messagingSenderId: import.meta.env.VITE_PUBLIC_MESSAGING_SENDER_ID, appId: import.meta.env.VITE_PUBLIC_APP_ID, measurementId: import.meta.env.VITE_PUBLIC_MEASUREMENT_ID }; // Initialize Firebase const app = initializeApp(firebaseConfig); //const analytics = getAnalytics(app); export const auth = getAuth(); export const db = getFirestore(app); // for image: import { getStorage, ref, uploadBytes } from "firebase/storage"; // new export const storage = getStorage(app)
create.jsx
import { auth, db } from "../utils/firebase" import { useAuthState } from "react-firebase-hooks/auth" import { useEffect, useState } from "react" import { AiOutlineCloseCircle } from "react-icons/Ai"; import { addDoc, collection, serverTimestamp } from "firebase/firestore"; // I need to upload the photo // create reference // create post, including reference import { getStorage, ref, uploadBytes } from "firebase/storage"; // new import { nanoid } from 'nanoid' import { storage } from '../utils/firebase' export default function Create(props){ const [post, setPost] = useState({imageSrc: undefined, title: "", description: ""})//maybe user id too?, probably fine without const [preview, setPreview] = useState(); const [user,loading] = useAuthState(auth); useEffect(() => { if (!post.imageSrc) { setPost({...post, imageSrc: undefined}) return } const objectUrl = URL.createObjectURL(post.imageSrc) setPreview(objectUrl) return () => URL.revokeObjectURL(objectUrl) }, [post.imageSrc]) const handleFile = async (e) => { if (!e.target.files || e.target.files.length === 0) { setPost({...post, imageSrc: undefined}) return } setPost({...post, imageSrc: e.target.files[0]}) } const submitPost = async (e) => { e.preventDefault(); const collectionRef = collection(db, "posts"); // uploading image first: const photoID = nanoid() // const storage = getStorage(); const storageRef = ref(storage, `images/${photoID}`); /////////////// PROBLEM IS HERE:///////////////////////////////////////////////////////// uploadBytes(storageRef, post.imageSrc).then(() => { console.log("successful upload!") })// this is the problem, idk if the imageSrc is the prob.... ////////////// END PROBLEM HERE ///////////////////////////////////////////////////////// // creating image reference: // normal stuff: await addDoc(collectionRef, { title: post.title, description: post.description, //imageRef: storageRef, // just connect the image reference here, but trough the firebase bucket// why no imageref... timestamp: serverTimestamp(), user: user.uid, avatar: user.photoURL, username: user.displayName, }); props.handleCreating() // closes this when done } return ( <div className="mainCreate"> <AiOutlineCloseCircle onClick={() => props.handleCreating()} className="closeIcon"/> <form onSubmit={submitPost}> <div className="imageBox"> {post.imageSrc ? <img className="imagePreview" src={preview}/> : <h2>No Image</h2>} {!post.imageSrc && <input type="file" onChange={handleFile}/>} </div> <textarea className="title" placeholder="Title" onChange={(e) => setPost({...post, title: e.target.value})} value={post.title} /> <p className={`lengthIndicator${post.title.length > 100 ? "Red" : ""}`}>{post.title.length}/100</p> <textarea className="description" placeholder="Description" onChange={(e) => setPost({...post, description: e.target.value})} value={post.description} /> <p className={`lengthIndicator${post.description.length > 300 ? "Red" : ""}`}>{post.description.length}/300</p> <button className="createButton" type="submit">Create</button> </form> </div> ) }
解决步骤(Bucket定位及CORS配置)
- 确认Storage Bucket名称:
- 打开Firebase控制台,进入「Storage」服务,顶部会显示Bucket地址(格式为
gs://<project-id>.appspot.com);或者直接取firebaseConfig中的storageBucket字段值。
- 打开Firebase控制台,进入「Storage」服务,顶部会显示Bucket地址(格式为
- 创建cors.json文件:
在项目根目录创建该文件,内容如下:[ { "origin": ["http://localhost:5173"], "method": ["GET", "POST", "PUT"], "maxAgeSeconds": 3600, "responseHeader": ["Content-Type", "Authorization"] } ] - 配置gsutil:
- 安装Google Cloud SDK,运行
gcloud init登录关联账号并选择对应Firebase项目。
- 安装Google Cloud SDK,运行
- 执行CORS设置命令:
终端运行:gsutil cors set cors.json gs://<你的storageBucket值> - 代码优化(可选):
uploadBytes是异步操作,建议用await包裹,避免addDoc提前执行:// 修改submitPost中的上传逻辑 try { await uploadBytes(storageRef, post.imageSrc); console.log("successful upload!"); // 可在此获取下载URL并存入Firestore // const downloadURL = await getDownloadURL(storageRef); } catch (error) { console.error("上传失败:", error); }
内容的提问来源于stack exchange,提问作者jkig
相关产品推荐
相关产品推荐

