admin管理员组

文章数量:1277875

I am trying to upload images to firebase firestorage from our Next.js app. We already have our firebase firestorage credentials set up in our environment variables, and I believe we have initiated firebase connection properly.

// Import the functions you need from the SDKs you need
import { initializeApp, getApps } from "firebase/app";
import { getAnalytics } from "firebase/analytics";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";

// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
  measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};

// Initialize Firebase
let firebaseApp;
if (!getApps().length) {
  firebaseApp = initializeApp(firebaseConfig);
}

// Initialize Firebase services
const auth = getAuth(firebaseApp);
const db = getFirestore(firebaseApp);

const STORAGE_FOLDER_PATH = `gs://${process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET}`;
const storage = getStorage(firebaseApp, STORAGE_FOLDER_PATH);

// Initialize Analytics and get analytics instance
let analytics;
if (typeof window !== "undefined") {
  analytics = getAnalytics(firebaseApp);
}

export { firebaseApp, auth, db, storage, analytics };

And this is the react component which responsible for the image uploading process. The upload image to firebase is in handleUpload function :

import { useState, useEffect, forwardRef, useImperativeHandle } from "react";
import { ref as fireRef, uploadBytes } from "firebase/storage";
import { nanoid } from "nanoid";
import { storage } from "@/lib/firebase";
import { toast } from "sonner";
import { DeleteBtn } from "@/components/ui/delete-button";

const SelectImages = forwardRef(({ allowNoImages = false }, ref) => {
  const [imageFiles, setImageFiles] = useState([]);
  const [isUploading, setIsUploading] = useState(false);

  const handleUpload = async () => {
    if (imageFiles.length === 0) {
      //handle condition if no image is selected
    }
    
    setIsUploading(true);
    const uploadPromises = imageFiles.map(async ({ file }) => {
      const filename = nanoid();
      const fileExt = file.name.split(".").pop();

      const storageRef = fireRef(
        storage,
        `images/${filename}.${fileExt}`
      );
      try{
        const res = await uploadBytes(storageRef, file);
        return res.metadata.fullPath;
      } catch (error) {
        toast.error(`Error uploading ${file.name}`, {
          description: error.message,
        });
        return null;
      }      
    });

    try {
      const uploadedUrls = await Promise.all(uploadPromises);      
      const validUrls = uploadedUrls.filter(url => url !== null);

      if (validUrls.length > 0) {
        toast.success(`Successfully uploaded ${validUrls.length} image${validUrls.length === 1 ? '' : 's'}`);        
      }
      setIsUploading(false);
      return validUrls;
    } catch (error) {
      toast.error("Error uploading images", {
        description: error.message,
      });
      setIsUploading(false);
      return [];
    }
  };

  // Expose handleUpload to parent component
  useImperativeHandle(ref, () => ({
    handleUpload
  }));

  const handleImageChange = (e) => {
    /*Function to add new image into the list to be uploaded*/
  };

  const removeImage = (indexToRemove) => {
    /*Function to remove an image from list to be uploaded*/
  };

  // Clean up object URLs when component unmounts
  useEffect(() => {
    return () => {
      imageFiles.forEach(image => {
        URL.revokeObjectURL(image.preview);
      });
    };
  }, []);

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-center w-full">
        <label className={`flex flex-col items-center justify-center w-full h-32 border-2 border-[#E8E1D5] border-dashed rounded-lg cursor-pointer bg-white hover:bg-gray-50 ${isUploading ? 'opacity-50 cursor-not-allowed' : ''}`}>
          <div className="flex flex-col items-center justify-center pt-5 pb-6">
            {isUploading ? (
              <>
                <LoadingIcon />
                <p className="text-sm text-[#2D6A4F]">Uploading images...</p>
              </>
            ) : (
              <>
                <UploadIcon />
                <p className="mb-2 text-sm text-[#2D6A4F]">
                  <span className="font-semibold">Click to upload</span> or drag and drop
                </p>
                <p className="text-xs text-[#2D6A4F]/70">PNG, JPG or WEBP (MAX. 5MB each)</p>
              </>
            )}
          </div>
          <input 
            type="file" 
            className="hidden" 
            multiple 
            accept="image/*"
            onChange={handleImageChange}
            disabled={isUploading}
          />
        </label>
      </div>

      {/* Image Preview Grid */}
      {/*Preview images to be uploaded here */}
        </div>
      )}      
    </div>
  );
});

export default SelectImages; 

This is our current rule :

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    // Public images folder - anyone can view, only authenticated users can upload
    match /images/{imageId} {
      allow read: if true;  // 

本文标签: reactjsNextjs fails to upload image to firebaseStack Overflow