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

Firebase Cloud Function使用uploadBytes报错及Storage模拟器问题

Firebase Cloud Functions使用uploadBytes上传至Storage的问题

我在编写Firebase Cloud Function时,尝试用uploadBytes上传文件到Firebase Cloud Storage,按照官方文档操作,但一直抛出错误:

TypeError: Cannot read properties of undefined (reading 'byteLength')

这个错误不在官方错误处理文档里,推测是找不到待上传文件,模拟器和云端环境都存在该问题。

1. uploadString测试正常,但存在超时问题

测试uploadString可以正常工作,代码如下:

import { initializeApp } from "firebase/app";
import * as functions from "firebase-functions";
import { getStorage, ref, uploadBytes, uploadString, connectStorageEmulator } from "firebase/storage";
const firebaseConfig = {
    apiKey: "12345",
    authDomain: "my-awesome-app.firebaseapp.com",
    databaseURL: "https://my-awesome-app.firebaseio.com",
    projectId: "my-awesome-app",
    storageBucket: "my-awesome-app.appspot.com",
    messagingSenderId: "12345",
    appId: "12345"
};
initializeApp(firebaseConfig);

export const StringMe = functions.firestore.document('StringMe/{userID}').onUpdate((change, context) => {
    const storage = getStorage();
    // const storageRef = ref(storage, 'message.txt'); // location to write to
    // connectStorageEmulator(storage, "localhost", 9199); // comment out to write to the cloud
    const storageRef = ref(storage, 'gs://my-awesome-app.appspot.com/Pictures/message.txt');
    const message = "Hello world!";

    async function uploadMessage() {
        try {
            await uploadString(storageRef, message);
            console.log("Uploaded a string!");
        } catch (error) {
            console.error(error);
        }
    };

    return uploadMessage()
});

日志显示Uploaded a string!和Finished "StringMe" in 417.150521ms,但60秒后会抛出超时错误:

functions: Your function timed out after ~60s. To configure this timeout, see
      https://firebase.google.com/docs/functions/manage-functions#set_timeout_and_memory_allocation.
⚠  Your function was killed because it raised an unhandled error.

暂时认为是Firebase CLI的bug,先忽略。

2. Storage模拟器无输出也无写入

切换到模拟器时,注释原storageRef并启用以下两行:

const storageRef = ref(storage, 'message.txt');
connectStorageEmulator(storage, "localhost", 9199);

此时除了超时外没有其他报错,但没有日志输出,也没有内容写入Storage,Storage模拟器为何无法工作?

3. 上传自定义模块中的字符串仍触发byteLength错误

自定义模块my-module.js内容:

export const file = "Hello world";

对应的上传代码:

import { initializeApp } from "firebase/app";
import * as functions from "firebase-functions";
import { getStorage, ref, uploadBytes, uploadString, connectStorageEmulator } from "firebase/storage";
import { file } from "./my-module.js";
const firebaseConfig = {
    apiKey: "...",
    authDomain: "...",
    databaseURL: "...",
    projectId: "...",
    storageBucket: "...",
    messagingSenderId: "...",
    appId: "..."
};
initializeApp(firebaseConfig);

export const ByteMe = functions.firestore.document('ByteMe/{userID}').onUpdate((change, context) => {
    const storage = getStorage(app);
    // const storageRef = ref(storage, 'hello.txt'); // location to write to
    // connectStorageEmulator(storage, "localhost", 9199); // comment out to write to the cloud
    const storageRef = ref(storage, 'gs://my-awesome-app.appspot.com/Pictures/hello.txt');

    const metadata = {
        contentType: 'text/plain',
    };

    async function uploadFile() {
        try {
            console.log(file);
            await uploadBytes(storageRef, file, metadata);
            console.log('Uploaded a file!');
        } catch (error) {
            console.error(error);
        }
    }

    return uploadFile();
});

日志输出Hello world(确认文件可被函数读取),但还是抛出相同的byteLength错误,为何uploadBytes无法读取该文件?
切换到模拟器也会触发相同错误。

4. 从API获取文件上传仍触发相同错误

尝试从API获取音频文件后上传,代码如下:

import { initializeApp } from "firebase/app";
import * as functions from "firebase-functions";
import { getStorage, ref, uploadBytes, uploadString, connectStorageEmulator } from "firebase/storage";
import got from 'got';

const firebaseConfig = {
    apiKey: "...",
    authDomain: "...",
    databaseURL: "...",
    projectId: "...",
    storageBucket: "...",
    messagingSenderId: "...",
    appId: "..."
};
initializeApp(firebaseConfig);

export const ByteAPI = functions.firestore.document('ByteAPI/{userID}').onUpdate((change, context) => {
    const storage = getStorage();
    // const storageRef = ref(storage, 'picture.jpg'); // location to write to
    // connectStorageEmulator(storage, "localhost", 9199); // comment out to write to the cloud
    const storageRef = ref(storage, 'gs://my-awesome-app.appspot.com/Pictures/winter.mp3');

    const metadata = {
        contentType: 'audio/mpeg',
    };

    async function uploadFile() {
        try {
            let file = await got('https://audio.oxforddictionaries.com/en/mp3/winter__us_2.mp3');
            await uploadBytes(storageRef, file, metadata);
            console.log('Uploaded a file!');
        } catch (error) {
            console.error(error);
        }
    }

    return uploadFile();
});

目标音频文件可正常访问,但无论云端还是模拟器,都抛出相同的byteLength错误。尝试上传Uint8Array结果一样,难道uploadBytes功能损坏了?


解决方案

核心问题:uploadBytes参数类型不匹配

uploadBytes要求第二个参数必须是Blob、File或Uint8Array类型,你传入的普通字符串、got响应对象都不符合要求,这才导致了byteLength读取错误。

分场景修复:

  1. 上传字符串(用uploadBytes)
    将字符串转换为Uint8Array后传入:
const fileBuffer = new TextEncoder().encode(file);
await uploadBytes(storageRef, fileBuffer, metadata);
  1. 处理API获取的文件(got库)
    got默认返回响应对象,需指定responseType: 'buffer'获取二进制数据,再传入响应体:
let response = await got('https://audio.oxforddictionaries.com/en/mp3/winter__us_2.mp3', { responseType: 'buffer' });
await uploadBytes(storageRef, response.body, metadata);
  1. 修复Storage模拟器不工作问题
  • 确保模拟器正确启动:运行firebase emulators:start --only storage
  • 调整调用顺序:必须先连接模拟器,再创建存储引用
    const storage = getStorage();
    connectStorageEmulator(storage, "localhost", 9199); // 先连接模拟器
    const storageRef = ref(storage, 'message.txt'); // 再创建引用
    
  • 检查端口是否冲突,默认Storage模拟器端口为9199
  • 调整函数超时时间:在firebase.json中配置
    {
      "functions": {
        "runtimeOptions": {
          "timeoutSeconds": 30
        }
      }
    }
    
  1. 解决函数超时问题
    服务端场景更推荐使用Firebase Admin SDK,而非Web版Storage SDK,兼容性更好:
    安装Admin SDK:
npm install firebase-admin

重构代码示例:

import * as functions from "firebase-functions";
import { initializeApp } from "firebase-admin/app";
import { getStorage } from "firebase-admin/storage";

initializeApp();

export const StringMe = functions.firestore.document('StringMe/{userID}').onUpdate(async (change, context) => {
  const bucket = getStorage().bucket();
  const file = bucket.file('Pictures/message.txt');
  await file.save("Hello world!", {
    contentType: 'text/plain'
  });
  console.log("Uploaded a string!");
});

内容的提问来源于stack exchange,提问作者Thomas David Kehoe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 18:40:40