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

Firebase Storage对象不存在错误:图片已上传却无法添加至云端

问题解决:Firebase Storage上传成功但无法获取下载URL

错误现象

每次尝试向Firebase添加图片时触发以下错误:

FirebaseError: Firebase Storage: Object 'items/Screenshot at May 22 07-33-37.png9573dc82-ec43-4789-88ec-e93727d6a11f' does not exist. (storage/object-not-found)

图片已成功上传至Firebase Storage,但无法获取下载URL并同步到Firestore。

问题根源

  1. 存储引用路径错误:创建Storage引用时额外添加了gs://cart-app-b469e.appspot.com前缀,而ref函数的第二个参数只需传入存储桶的相对路径,带前缀会导致实际存储路径与查询路径不匹配。
  2. 异步操作顺序混乱:uploadBytes是异步操作,但代码未等待其完成就直接调用getDownloadURL,此时文件可能还未完成上传,触发"对象不存在"错误。
  3. 状态逻辑不一致:newItemImage初始化为空字符串,但判断条件用newItemImage == null,逻辑不匹配。

修复后的完整代码

import React, { useState, useEffect } from 'react';
import { db, storage } from './../../config/config';
import { ref, uploadBytes, getDownloadURL } from 'firebase/storage';
import { getDocs, collection, addDoc } from 'firebase/firestore';
import { ItemsList, AddForm } from './shopStyle';
import { v4 } from 'uuid';

export const Shop = () => {
  const [items, setItems] = useState([]);
  const itemsRef = collection(db, "items");

  // 新商品状态
  const [newItemName, setNewItemName] = useState("");
  const [newItemPrice, setNewItemPrice] = useState(0);
  // 初始化改为null,与文件对象的空状态匹配
  const [newItemImage, setNewItemImage] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const data = await getDocs(itemsRef);
        const filteredData = data.docs.map((doc) => ({
          ...doc.data(),
          id: doc.id,
        }));
        setItems(filteredData);
      } catch (err) {
        console.error(err);
      }
    };
    fetchData();
  }, []);

  function handleImage(e) {
    let pickedFile;
    if (e.target.files && e.target.files.length > 0) {
      pickedFile = e.target.files[0];
      setNewItemImage(pickedFile);
      console.log(pickedFile);
    }
  }

  const addItems = async (e) => {
    e.preventDefault();

    if (!newItemImage) return;

    // 移除gs://前缀,直接使用存储桶相对路径
    const imageRef = ref(storage, `items/${newItemImage.name + v4()}`);
    
    try {
      // 等待上传完成后再执行后续操作
      await uploadBytes(imageRef, newItemImage);
      alert("Image uploaded");

      // 上传完成后获取下载URL
      const downloadURL = await getDownloadURL(imageRef);

      const newItem = {
        Image: downloadURL,
        Name: newItemName,
        Price: newItemPrice,
      };

      await addDoc(itemsRef, newItem);

      // 清空输入字段
      setNewItemImage(null);
      setNewItemName("");
      setNewItemPrice(0);
    } catch (err) {
      console.log(err);
    }
  };
  
  return (
    <div>
      <AddForm onSubmit={addItems}>
        <input
          accept="image/*"
          id="icon-button-file"
          type="file"
          onChange={handleImage}
        />
        <input
          type="text"
          placeholder="name"
          value={newItemName}
          onChange={(e) => setNewItemName(e.target.value)}
        />
        <input
          type="number"
          placeholder="price"
          value={newItemPrice}
          onChange={(e) => setNewItemPrice(e.target.value)}
        />
        <button type="submit">Add</button>
      </AddForm>
      <ItemsList>
        {items.map((item) => (
          <div key={item.id}>
            <img src={item.Image} alt={item.Name} />
            <h1>{item.Name}</h1>
            <h4>{item.Price}</h4>
          </div>
        ))}
      </ItemsList>
    </div>
  );
};

核心修复说明

  • 路径修正:创建imageRef时移除gs://前缀,确保引用路径与实际存储路径完全一致。
  • 异步等待:使用await等待uploadBytes完成,保证文件上传成功后再执行获取下载URL的操作。
  • 状态逻辑统一:将newItemImage初始化为null,判断时用!newItemImage,逻辑更严谨。
  • 表单优化:将按钮type设为submit,配合表单的onSubmit事件,避免重复绑定点击事件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 07:00:22