我正在使用 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 捕获。它确实被抓住了,但它却以“未被抓住”的方式从某个地方溜走了。
错误来自这里的第二个代码块:
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
意味着您在记录错误后重新抛出错误。如果您不想这样做,请删除此行。