从手机上传文件时,Firebase 存储(网络)无法正常工作

Posted

技术标签:

【中文标题】从手机上传文件时,Firebase 存储(网络)无法正常工作【英文标题】:Firebase Storage (web) not working when files are uploaded from phone 【发布时间】:2021-10-06 09:29:26 【问题描述】:

我正在使用 Firebase 创建一个网站。用户应该能够上传和更新他们的个人资料图片,只要它小于 10mb,并且是 .jpg、.png 或 .gif 文件。

应该发生什么:

    用户上传有效图片 在 Firebase 存储中创建或更新引用 /users/uid/profileImage 使用 getDownloadURL() 方法获取图片的 URL,并将其作为文本存储在 Firestore 中的用户个人资料信息下 使用该 URL 作为头像的src

当我尝试在我的计算机 (Windows 10) 上执行此操作时,它运行良好。但是,当我尝试在手机(iPhone 8;ios 14.7.1)上执行此操作时,它不起作用。从手机上传的图片到达/users/uid/profileImage,但由于权限问题,即使用户按照规则在手机浏览器上进行了身份验证,也无法正确获取downloadURL

以下是 (1) 获取文件和 (2) 更新用户头像的代码:

// Grab dp img and store it in file var
let file = 
const chooseFile = (e) => 
    // Get the file from local machine
    file = e.target.files[0]
    console.log(file )


// Store dp in storage as file, and db as link
const updateDp = (currentUser) => 
    // Check if new dp has been added/exists.
    if ("name" in file) 
        // Check if uploaded file is an image
        if (file.type !== "image/jpeg" && file.type !== "image/png" && file.type !== "image/gif") 
            alert("You can only upload .jpeg, .jpg, .png and .gif under 10mb")
            return
        

        // Check image file size
        if (file.size/1024/1024>10) 
            alert("The image size must be under 10mb")
            return
        

        // Create storage ref & put the file in it
        storage
            .ref("users/" + currentUser.uid + "/profileImage")
            .put(file)
            .then(() => 
                // success => get download link, put it in DB, update dp img src
                storage
                    .ref("users/" + currentUser.uid + "/profileImage")
                    .getDownloadURL()
                    .then(imgURL => 
                        db
                            .collection("users")
                            .doc(currentUser.uid)
                            .set(
                                dp_URL: imgURL,
                                dp_URL_last_modified: file.lastModifiedDate
                            , 
                                merge: true
                            )
                        document.querySelector("#nav_dp").src = imgURL;
                    )
                console.log("success")
            ).catch(() => 
                console.log(error.message)
            )
     else 
        console.log("Empty/no file")
    


以下是我的 Firebase 存储规则:

rules_version = '2';
service firebase.storage 
  match /b/bucket/o 
    match /users/uid/profileImage 
      allow read: if request.auth!=null;
      allow write: if request.auth!=null && request.auth.uid == uid;
    
  


【问题讨论】:

【参考方案1】:

除了console.log("success") 会在您获得downloadURL 之前记录,因为getDownloadURL() 返回一个Promise,对我来说安全规则和代码看起来不错。尝试将您的函数更改为异步函数,如下所示:

// Store dp in storage as file, and db as link
const updateDp = async (currentUser) => 
  //             ^^^^^
  // Check if new dp has been added/exists.
  if ("name" in file) 
    try 
      // Check if uploaded file is an image
      if (
        file.type !== "image/jpeg" &&
        file.type !== "image/png" &&
        file.type !== "image/gif"
      ) 
        alert("You can only upload .jpeg, .jpg, .png and .gif under 10mb");
        return;
      

      // Check image file size
      if (file.size / 1024 / 1024 > 10) 
        alert("The image size must be under 10mb");
        return;
      

      // Create storage ref & put the file in it
      const userPicRef = storage.ref(
        "users/" + currentUser.uid + "/profileImage"
      );
      await userPicRef.put(file);
      console.log("Image uploaded")
      // success => get download link, put it in DB, update dp img src
      const imgURL = await UserPicRef.getDownloadURL();
      console.log(`Image URL: $imgURL`)
      await db.collection("users").doc(currentUser.uid).set(
        
          dp_URL: imgURL,
          dp_URL_last_modified: file.lastModifiedDate,
        ,
        
          merge: true,
        
      );
      console.log("Document Added")
      document.querySelector("#nav_dp").src = imgURL;
     catch (error) 
      console.log(error);
    
   else 
    console.log("Empty/no file");
  
;

【讨论】:

这并没有解决最初的问题:从任何手机(至少是 iOS)上传图像都不起作用。从手机收到的文件类型似乎是 JSON,这导致了问题。这在“网络”选项卡中可以看到,因为从 PC 和手机上传的 img 都是相同的,但手机图像类型是 JSON。 @SwapnilIqbal 你指的是什么文件类型?可以分享一下截图吗? imgur.com/a/WzjdNue 如您所见,从我的手机上传的图像在某种程度上是 JSON,即使在 Firebase 控制台中,我将其视为 jpeg。 @SwapnilIqbal 你能点击那个请求然后在里面分享一个响应标签的截图吗? imgur.com/IXZRH2U 这是代码试图获取的链接,并抛出 403 错误:firebasestorage.googleapis.com/v0/b/…【参考方案2】:

回答我自己的问题。

原来,我使用的是file.lastModifiedDate,这是一种折旧的方法。它适用于在 android 上运行的 Google Chrome 应用程序,但不适用于 iOS。

为了解决这个问题,我改用了file.lastModified

【讨论】:

以上是关于从手机上传文件时,Firebase 存储(网络)无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

无法上传到 Firebase 存储/权限被拒绝

无法从颤振网络将图像上传到 Firebase 存储

使用 firebase 功能将图像上传到云存储错误

Firebase连接到后端时如何上传到前端的Firebase存储?

从多个文件上传 Firebase 存储中获取下载 url

Firebase 存储 - 在 Android 中上传多个图像文件