Node.js上传视频至Firebase Storage时bytelength错误的解决求助
Node.js视频上传Firebase Storage触发bytelength错误(开启express-fileupload临时文件时)
问题场景
开发Node.js服务器,用于将视频上传至Firebase Storage、图片上传至Cloudinary。当使用express-fileupload开启useTempFiles选项创建临时文件时,图片可成功上传至Cloudinary,但视频上传至Firebase Storage时触发bytelength相关错误。
相关代码
Index.ts
import "dotenv/config"; import "./configs/init_mongodb"; import express, { Request, Response, Application } from "express"; import cors from "cors"; import verifyAuthor from "./middleware/verifyAuthor"; import bodyParser from "body-parser"; import morgan from "morgan"; import upload from "express-fileupload"; import adminRouter from "./routes/admin"; const app: Application = express(); app.use(express.json()); app.use(cors()); app.use(morgan("dev")); app.use(upload( { useTempFiles: true, } )); app.use(express.urlencoded({ extended: true })); app.use(bodyParser.urlencoded({ extended: true })); app.get("/admin", verifyAuthor, (req: Request, res: Response) => { res.send("Admin Page"); }); app.use("/admin", verifyAuthor, adminRouter); app.get("/client", verifyAuthor, (req: Request, res: Response) => { res.send("Client Page"); }); app.listen(process.env.PORT || 5000, () => { console.log(`Server is running on port ${process.env.PORT || 5000}`); });
firebase.ts
import firebaseStorageConfig from "../configs/firebaseConfig"; import { getDownloadURL, ref, uploadBytes, deleteObject, } from "firebase/storage"; import { v4 } from "uuid"; // upload video to firebase storage export const uploadVideo = async (video: any) => { const storageRef = ref(firebaseStorageConfig, `videos/${v4()}`); // 未创建临时文件时的写法 // await uploadBytes(storageRef, video.data, { // contentType: video.mimetype, // }); // 创建临时文件后的错误写法 await uploadBytes(storageRef, video.tempFilePath, { contentType: video.mimetype, }); const videoUrl = await getDownloadURL(storageRef); return videoUrl; }; // delete files from firebase storage export const deleteFiles = async () => { try { const storageRef = ref(firebaseStorageConfig); await deleteObject(storageRef); } catch (error) { console.log(error); } };
admin.ts
import express, { NextFunction, Request, Response } from "express"; import { uploadVideo } from "../helpers/firebase"; import { uploadImage } from "../helpers/cloudnary"; import { deleteFiles } from "../helpers/delfiles"; import { insertData } from "../helpers/mongoDb"; import { v4 } from "uuid"; const router = express.Router(); const saveData = async (req: Request, res: Response, next: NextFunction) => { try { console.log(req.files); const video: any = req.files?.video; const image: any = req.files?.image; const videoUrl = await uploadVideo(video); const imageUrl = await uploadImage(image); const linksBody = [...req.body.links]; const linkLen = linksBody.length; const links = []; if (linkLen > 0) { console.log("body", linksBody); if (linkLen === 1) { links.push(JSON.parse(linksBody[0])); } else { linksBody.map((link: any) => { links.push(JSON.parse(link)); }); } } const tags = req.body.tags.split(",").trim(); console.log("tags", tags); const data = { id: v4(), projectName: req.body.projectName, projectDescription: req.body.about, otherUrls: links, projectVideoUrl: videoUrl, projectImageUrl: imageUrl, projectTags: tags, }; const portfolio_data = await insertData(data); deleteFiles(); res.status(200).send({ status: "Ok", data: portfolio_data }); } catch (err) { console.log(err); next(err); } }; router.post("/save", saveData); export default router;
问题原因
Firebase Storage的uploadBytes方法要求第二个参数为Blob、Uint8Array或ArrayBuffer类型。开启useTempFiles后,video.tempFilePath是字符串格式的临时文件路径,直接传入uploadBytes会导致类型不匹配,触发bytelength相关错误。而Cloudinary的SDK支持直接传入文件路径,因此图片上传不受影响。
解决方案
通过fs.readFile将临时文件读取为Buffer格式,再传入uploadBytes方法。以下是修改后的核心代码:
调整admin.ts中的视频上传逻辑
const saveData = async (req: Request, res: Response, next: NextFunction) => { try { console.log(req.files); const video: any = req.files?.video; const image: any = req.files?.image; let videoUrl; // 使用Promise版fs读取临时文件为Buffer const fs = require('fs').promises; const buffer = await fs.readFile(video.tempFilePath); video.data = buffer; videoUrl = await uploadVideo(video); const imageUrl = await uploadImage(image); // 修正标签处理逻辑:split后逐个trim const tags = req.body.tags.split(",").map(tag => tag.trim()); const linksBody = [...req.body.links]; const linkLen = linksBody.length; const links = []; if (linkLen > 0) { linksBody.forEach(link => links.push(JSON.parse(link))); } const data = { id: v4(), projectName: req.body.projectName, projectDescription: req.body.about, otherUrls: links, projectVideoUrl: videoUrl, projectImageUrl: imageUrl, projectTags: tags, }; const portfolio_data = await insertData(data); deleteFiles(); res.status(200).send({ status: "Ok", data: portfolio_data }); } catch (err) { console.log(err); next(err); } };
恢复firebase.ts中的正确上传写法
export const uploadVideo = async (video: any) => { const storageRef = ref(firebaseStorageConfig, `videos/${v4()}`); await uploadBytes(storageRef, video.data, { contentType: video.mimetype, }); const videoUrl = await getDownloadURL(storageRef); return videoUrl; };
内容的提问来源于stack exchange,提问作者Kartik Fulara
相关产品推荐
相关产品推荐

