无法从 Firebase Cloud Storage 捕获错误

问题描述 投票:0回答:1

我正在使用 React、TypeScript 和 Firebase 服务。 我被 Firebase 存储服务困住了几天,我尽力弄清楚自己,查看了 Firebase 文档、论坛、YouTube - 没有运气......请帮忙!

我有一个

storageService.ts
文件,导出 2 个函数 -
uploadFile
deleteFile
。 注释掉的代码片段是我让它工作的尝试:

import {
  ref,
  uploadBytesResumable,
  getDownloadURL,
  deleteObject,
} from "firebase/storage";
import { storage } from "./config";

const uploadFile = async (
  file: Blob | Uint8Array | ArrayBuffer,
  fullFilePath: string,
  progressCallback: (progress: number) => void
) => {
  const uploadRef = ref(storage, fullFilePath);
  const uploadTask = uploadBytesResumable(uploadRef, file);

  uploadTask.on(
    "state_changed",
    (snapshot) => {
      const progress = Math.round(
        (snapshot.bytesTransferred / snapshot.totalBytes) * 100
      );
      progressCallback(progress);
    },
    (error) => {
      console.log("Caught inside on()");
      console.log("This is what we caught: ", error);
      progressCallback(-1);
      throw error;
    }
    // () => {
    //   //from Docs https://firebase.google.com/docs/storage/web/upload-files
    //   // Upload completed successfully, now we can get the download URL
    //   getDownloadURL(uploadTask.snapshot.ref).then((downloadUrl) => {
    //     console.log("File available at", downloadUrl);
    //     return downloadUrl;
    //   });
    // }
  );

  // uploadTask.then(() => {
  //   getDownloadURL(uploadTask.snapshot.ref)
  //     .then((downloadUrl) => {
  //       console.log("File available at", downloadUrl);
  //       return downloadUrl;
  //     })
  //     .catch((error) => {
  //       console.log("Caught outside...");
  //       throw error;
  //     });
  // });

  try {
    await uploadTask;
    const downloadUrl = await getDownloadURL(uploadTask.snapshot.ref);
    return downloadUrl;
  } catch (error) {
    console.log("Catching error for the second time!");
    console.log("HERE IT IS ", error);
    throw new Error("Error from uplodTask");
  }
};

const deleteFile = (fileDownloadUrl: string) => {
  const decodedUrl = decodeURIComponent(fileDownloadUrl);
  const startIndex = decodedUrl.indexOf("/o/") + 3;
  const endIndex = decodedUrl.indexOf("?");
  const filePath = decodedUrl.substring(startIndex, endIndex);

  const fileRef = ref(storage, filePath);
  return deleteObject(fileRef);
};

const FirebaseStorageService = {
  uploadFile,
  deleteFile,
};

export default FirebaseStorageService;

另外,我有

file-upload-progress.component.tsx
文件,它是一个使用
uploadFile
函数的 React 组件(我正在使用样式化组件,这就是为什么有些标签具有自定义名称):

import { ChangeEvent, FC, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import { v4 as uuidv4 } from "uuid";
import { FaUpload } from "react-icons/fa";

import FirebaseStorageService from "../../../firebase/storageService";
import Button from "../button/button.component";
import { BackButtonContainer } from "../../../global.styles";
import {
  FileInput,
  FileInputLabel,
  ProgressBar,
  ProgressInfo,
  UploadContainer,
} from "./file-upload-progress.styles";

type FileUploadProgressProps = {
  basePath: string;
  navigateAfterUpload: string;
  handleUploadFinish: (downloadUrl: string) => void;
  pending: boolean;
};

const FileUploadProgress: FC<FileUploadProgressProps> = ({
  basePath,
  navigateAfterUpload,
  handleUploadFinish,
  pending,
}) => {
  const navigate = useNavigate();

  const [uploadProgress, setUploadProgress] = useState(-1);
  const [fileUrl, setFileUrl] = useState("");

  const fileInputRef = useRef<HTMLInputElement | null>(null);

  const handleFileChanged = async (event: ChangeEvent<HTMLInputElement>) => {
    const files = event.target.files;
    if (files && files.length !== 0) {
      const file = files[0];
      const generatedFileId = uuidv4();
      try {
        const downloadUrl = await FirebaseStorageService.uploadFile(
          file,
          `${basePath}/${generatedFileId}`,
          setUploadProgress
        );
        setFileUrl(downloadUrl);
        //send downloadUrl to database
        if (downloadUrl) {
          handleUploadFinish(downloadUrl);
        }
      } catch (error) {
        if (error instanceof Error) {
          if (fileInputRef.current) {
            fileInputRef.current.value = "";
          }
          console.log("Catching in FileUploadProgress component!", error);
          alert(error.message);
          return;
        } else {
          alert("Error is not instance of Error....");
          return;
        }
      }
    } else {
      alert("File select failed. Please try again");
      return;
    }
  };

  return (
    <UploadContainer>
      <FileInput
        type="file"
        id="fileInput"
        accept="application/pdf,image/*"
        onChange={handleFileChanged}
        ref={fileInputRef}
        hidden={uploadProgress > -1 || !!fileUrl || pending}
      />
      {!fileUrl && uploadProgress < 0 && !pending && (
        <FileInputLabel htmlFor="fileInput">
          <div>
            <FaUpload size={24} />
          </div>
          <div>Select a File</div>
        </FileInputLabel>
      )}
      {!fileUrl && uploadProgress > -1 && (
        <ProgressBar>
          <label htmlFor="file">Upload Progress:</label>
          <br />
          <progress id="file" value={uploadProgress} max="100">
            {uploadProgress}%
          </progress>
          <ProgressInfo>{uploadProgress}%</ProgressInfo>
        </ProgressBar>
      )}
      {(fileUrl || pending) && (
        <div className="image-preview">
          <p>
            Your document has been uploaded successfully! It may take us up to
            72 hours to review it, but we'll do our best to be quicker than
            that.
          </p>
          <BackButtonContainer>
            <Button
              buttonType="green"
              onClick={() => navigate(navigateAfterUpload)}
            >
              Ok
            </Button>
          </BackButtonContainer>
        </div>
      )}
    </UploadContainer>
  );
};

export default FileUploadProgress;

实际上一切正常,除非请求被 Firebase 存储安全规则拒绝。我有一组规则,允许将身份验证用户写入带有其 ID 的文件夹,仅接受某些类型和大小的文件。

当我上传一个通过规则的文件时,一切都很高兴,但是当我从存储中收到错误响应时,问题就出现了,尽管在任何地方都捕获了它(并记录了),但它仍然会漏掉并导致应用程序崩溃,并显示“未捕获(承诺) )FirebaseError:Firebase存储:用户无权访问...”

这是我的日志(我已手动替换了下面文本中的实际存储路径,以防万一):

Caught inside on() 
                           storageService.ts:20
-----------------------------------------------------------------
This is what we caught:  FirebaseError: Firebase Storage: User does not have permission to access '<storage file path here>'. (storage/unauthorized)
    FirebaseError errors.ts:78
    StorageError error.ts:38
    unauthorized error.ts:168
    errorHandler requests.ts:120
    backoffDone request.ts:163
    triggerCallback backoff.ts:66
    responseHandler backoff.ts:84
    node_modules bundle.js:41748
    promise callback*doTheRequest request.ts:109
    node_modules bundle.js:41438
    setTimeout handler*callWithDelay backoff.ts:68
    start backoff.ts:133
    start_ request.ts:181
    node_modules bundle.js:41709
    NetworkRequest request.ts:54
    makeRequest request.ts:270
    _makeRequest service.ts:301
    node_modules bundle.js:43468
    node_modules bundle.js:43371
    promise callback*_resolveToken bundle.js:43367
    _oneShotUpload task.ts:364
    _start task.ts:200
    node_modules bundle.js:43319
    UploadTask bundle.js:43316
    uploadBytesResumable$1 reference.ts:284
    uploadBytesResumable api.ts:162
    uploadFile storageService.ts:7
    handleFileChanged file-upload-progeress.component.tsx:43
    React 23
    tsx index.tsx:7
    factory react refresh:3
    Webpack 3
                                            storageService.ts:23

----------------------------------------------------------------------
Catching error for the second time! 
                                            storageService.ts:55
----------------------------------------------------------------------

HERE IT IS  FirebaseError: Firebase Storage: User does not have permission to access '<storage file path here>'. (storage/unauthorized)
    FirebaseError errors.ts:78
    StorageError error.ts:38
    unauthorized error.ts:168
    errorHandler requests.ts:120
    backoffDone request.ts:163
    triggerCallback backoff.ts:66
    responseHandler backoff.ts:84
    node_modules bundle.js:41748
    promise callback*doTheRequest request.ts:109
    node_modules bundle.js:41438
    setTimeout handler*callWithDelay backoff.ts:68
    start backoff.ts:133
    start_ request.ts:181
    node_modules bundle.js:41709
    NetworkRequest request.ts:54
    makeRequest request.ts:270
    _makeRequest service.ts:301
    node_modules bundle.js:43468
    node_modules bundle.js:43371
    promise callback*_resolveToken bundle.js:43367
    _oneShotUpload task.ts:364
    _start task.ts:200
    node_modules bundle.js:43319
    UploadTask bundle.js:43316
    uploadBytesResumable$1 reference.ts:284
    uploadBytesResumable api.ts:162
    uploadFile storageService.ts:7
    handleFileChanged file-upload-progeress.component.tsx:43
    React 23
    tsx index.tsx:7
    factory react refresh:3
    Webpack 3
                                             storageService.ts:56
-----------------------------------------------------------------------

Catching in FileUploadProgress component! Error: Error from uplodTask
    uploadFile storageService.ts:57
    handleFileChanged file-upload-progeress.component.tsx:43
    React 23
    tsx index.tsx:7
    factory react refresh:3
    Webpack 3
                              file-upload-progeress.component.tsx:58
-----------------------------------------------------------------------

Uncaught (in promise) FirebaseError: Firebase Storage: User does not have permission to access '<storage file path here>'. (storage/unauthorized)
    FirebaseError errors.ts:78
    StorageError error.ts:38
    unauthorized error.ts:168
    errorHandler requests.ts:120
    backoffDone request.ts:163
    triggerCallback backoff.ts:66
    responseHandler backoff.ts:84
    node_modules bundle.js:41748
    promise callback*doTheRequest request.ts:109
    node_modules bundle.js:41438
    setTimeout handler*callWithDelay backoff.ts:68
    start backoff.ts:133
    start_ request.ts:181
    node_modules bundle.js:41709
    NetworkRequest request.ts:54
    makeRequest request.ts:270
    _makeRequest service.ts:301
    node_modules bundle.js:43468
    node_modules bundle.js:43371
    promise callback*_resolveToken bundle.js:43367
    _oneShotUpload task.ts:364
    _start task.ts:200
    node_modules bundle.js:43319
    UploadTask bundle.js:43316
    uploadBytesResumable$1 reference.ts:284
    uploadBytesResumable api.ts:162
    uploadFile storageService.ts:7
    handleFileChanged file-upload-progeress.component.tsx:43
    React 23
    tsx index.tsx:7
    factory react refresh:3
    Webpack 3
                                 errors.ts:78

​

最后一条日志是红色的,它会使应用程序崩溃 “未捕获的运行时错误: 错误 Firebase 存储:用户无权访问...”

任何帮助或推动正确的方向将不胜感激!

我的

uploadFile()
函数抛出错误,应该由 React 组件内的 try-catch 捕获。它确实被抓住了,但它却以“未被抓住”的方式从某个地方溜走了。

reactjs firebase error-handling google-cloud-storage runtime-error
1个回答
0
投票

错误来自这里的第二个代码块:

uploadTask.on(
  "state_changed",
  (snapshot) => {
    const progress = Math.round(
      (snapshot.bytesTransferred / snapshot.totalBytes) * 100
    );
    progressCallback(progress);
  },
  (error) => {
    console.log("Caught inside on()");
    console.log("This is what we caught: ", error);
    progressCallback(-1);
    throw error; // 👈
  }

那里的

throw error
意味着您在记录错误后重新抛出错误。如果您不想这样做,请删除此行。

© www.soinside.com 2019 - 2024. All rights reserved.