You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 23:10:25