为啥我没有在我的 react 应用程序中获取 firebase 存储文件 url?

Posted

技术标签:

【中文标题】为啥我没有在我的 react 应用程序中获取 firebase 存储文件 url?【英文标题】:Why am I not getting firebase storage files url in my react app?为什么我没有在我的 react 应用程序中获取 firebase 存储文件 url? 【发布时间】:2021-08-04 20:01:55 【问题描述】:

在我的 React 应用程序中,我主要拥有三个连接到 firebase 的功能。 firebase auth,实时聊天,这第三个需要 firebase 存储。我想上传带有聊天消息的图像。 当我尝试上传图片时,当我尝试 console.log(url) 时,控制台会出现此错误 我想获取下载的图像 url 并将其存储在我的 firestore 数据库中,然后在我的 Message.js 组件中使用该 url。

我的 Chat.js 组件

  const [messages, setMessages] = useState([]);
  const [assets, setAssets] = useState(null);

  useEffect(() => 
    if (channelId) 
      db.collection("channels")
        .doc(channelId)
        .collection("messages")
        .orderBy("timestamp", "desc")
        .onSnapshot((snapshot) => 
          setMessages(snapshot.docs.map((doc) => doc.data()));
        );
    
  , [channelId]);

  const sendMessage = (e) => 
    e.preventDefault();
    const uploadTask = storage.ref(`assets_discord/$assets.name`).put(assets);
    uploadTask.on("state_changed", () =>  
      storage
        .ref("assetsdiscord")
        .child(assets.name)
        .getDownloadURL()
        .then((url) => 
          db.collection("assetUrl").add(
            imgUrl: url,
          );
          console.log(url);
          setAssets(null);
        );
      );
      db.collection("channels").doc(channelId).collection("messages").add(
        user: user,
        message: input,
        timestamp: firebase.firestore.FieldValue.serverTimestamp(),
      );
      
    setInput("");
  ;

  const hideInput = (e) => 
    e.preventDefault();
    setShowInput(!showInput);
  ;

  return (
    <div className="chat">
      channelId ? (
        <>
          <ChatHeader channelName=channelName />
          <div className="chat__messages">
            messages.map((message) => (
              <Message
                user=message.user
                message=message.message
                timestamp=message.timestamp
                assetUrl=message.imgUrl
              />
            ))
          </div>
          <div className="chat__input">
            showInput ? (
              <>
                <form action="#">
                  <label htmlFor="imgFiles" className="upload__img">
                    <AddCircle fontSize="large" />
                  </label>
                  <input
                    type="file"
                    id="imgFiles"
                    className="hidden"
                    accept="image/*"
                    onChange=(e) => 
                      if (e.target.files[0]) 
                        setAssets(e.target.files[0]);
                      
                    
                  />
                  <input
                    disabled=!channelId
                    value=input
                    onChange=(e) => setInput(e.target.value)
                    type="text"
                    placeholder=`Send Message to #$channelName`
                  />
                  <button
                    onClick=sendMessage
                    className="chat__inputButton"
                    type="Submit"
                  >
                    Send Message
                  </button>
                  <button onClick=hideInput>Hide</button>
                </form>
              </>
            ) : (
              <p
                onClick=() => setShowInput(!showInput)
                className="show__input"
              >
                Show
              </p>
            )
          </div>
        </>
      ) : (
        <>
          <div className="chat__selectRoom">
            <ArrowLeftIcon
              style= fontSize: "30px" 
              className="arrow__left"
            />
            <h3>Select Any Room to get Started</h3>
          </div>
        </>
      )
    </div>
  );

消息组件

const Message = ( user, timestamp, message, assetUrl ) => 
  // console.log(assetUrl);
  return (
    <div className="message">
      <Avatar src=user.photo />
      <div className="message__info">
        <h4>
          user.displayName
          <span className="message__timestamp">
            new Date(timestamp?.toDate()).toUTCString()
          </span>
        </h4>
        <p>message</p>
        /*
         <ImageUpload assetUrl=assetUrl /> 
       */
        <img src=assetUrl  />
      </div>
    </div>
  );
;

firebase sequrity 规则

service cloud.firestore 
  match /databases/database/documents 
    match /document=** 
      allow read, write;
    
  

service firebase.storage 
  match /b/bucket/o 
    match /allPaths=** 
      allow read, write: if true;
    
  

Link to live website

【问题讨论】:

检查文件地址是否有误。确定该文件不存在,请检查您从 api 获取的 url。 是的,当我单击 firebase api URL 时,它表示文件不存在,我正在获取 api 的 url 也托管在 firebase 上,但我正在使用 netlify 链接进行生产。你是说我应该检查我的 Firebase 网址? 是的,检查您获取的网址并手动下载文件。至少您可以知道问题出在哪里,在 Firebase 规则中或在您的代码中。 我访问了控制台错误 url 但它显示我对象这个对象:“错误”:“代码”:403,“消息”:“权限被拒绝。无法执行此操作”我不明白怎么了? 我们明白了,问题出在 Firebase 规则中。 Google 提供了安全规则,我们可以通过这些规则控制人们访问我们的 Firebase 存储。我正在发布一个答案,请检查它。 【参考方案1】:

转到 firebase 控制台,然后选择您正在处理的项目,然后转到存储,然后转到规则。

如果您使用的是 Firestore 或数据库,请检查规则。另一个问题可能是您没有添加项目的 SHA。我们允许每个人更改存储方式的公共访问权限。

在您的情况下,正如您所评论的,问题可能是安全访问。 Here is a link to google documenations

我建议您在使用任何平台(如 Amazon AWS、firebase 或任何类型的 API)之前阅读文档。

另一个检查 - 检查文件的地址,我重新检查了错误。您的安全规则是正确的,我认为您应该使用文档中的一些示例。

【讨论】:

感谢 Vijay 的回答,我更改了存储规则,但现在我上传了显示错误代码 404 而不是 403 的图像。未捕获(承诺)FirebaseError: Firebase Storage: Object 'assetsdiscord/Screenshot ( 226).png' 不存在。 (storage/object-not-found) "error": "code": 404, "message": "Not Found. could not get object", "status": "GET_OBJECT" 我查看了图片的api链接,如下:firebasestorage.googleapis.com/v0/b/… 也许我的 react 应用有问题? 你的应用和firebase服务器没有问题,你应该冷静和耐心。看到它说找不到对象(我不知道 javascript,因为我是一名 android 开发人员),但在 java 中这意味着 StorageReferece 未初始化。根据错误可能有两个错误,一个是对象有问题,第二个是文件的位置(您要上传的文件或您要上传的位置)不正确。耐心一点,一步一步看,错在哪里。 感谢 Vijay 的所有帮助,我会看一看。【参考方案2】:

当您提到上传时,您使用的是“assets_discord”,但是当您想要获取 URL 时,您指的是“assetsdiscord”

【讨论】:

以上是关于为啥我没有在我的 react 应用程序中获取 firebase 存储文件 url?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Postman 在我的 React 应用程序中接收到 express 会话 cookie 而不是我的 post 请求

React Native 已经有了异步存储。为啥我应该在我的 react native 应用中使用 Redux 和 Redux Thunk?

为啥我的 Apollo 缓存更新没有反映在我的查询中?

为啥 CORS 不能在我的 express/react 应用程序上运行?

为啥我的 react 应用在 html 的正文中没有出现脚本标签?

为啥 setState() 在我的情况下不能在 React 中工作?