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

Firebase Storage触发云函数报bucket属性未定义TypeError

错误根因
  • 核心报错来自Cloud Functions Storage触发器API版本不兼容:参考的5年前旧版代码适配的是老版firebase-functions,firebase-functions@3.x及以上版本中,onFinalize回调的第一个参数直接就是存储对象实例,不存在event.data嵌套,所以取object.bucket时实际访问的是undefined.bucket,直接抛出类型错误。
  • 其次@google-cloud/vision@2.x版本的类型引用方式变更,旧的Vision.v1.types.Feature.Type.XXX路径已经失效,直接传对应类型字符串即可,否则会触发类型不存在的报错。
  • 最后Swift端存在文件名不匹配的逻辑问题:上传时固定用了images/file.png作为存储路径,但是监听Firestore时却生成了新的UUID作为文档ID,两边路径完全不对应,就算云函数正常写入也监听不到数据。
修复方案

1. 替换云函数index.js代码

const Vision = require('@google-cloud/vision');
const vision = new Vision.ImageAnnotatorClient();
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp(); // 新版admin初始化无需传入functions.config().firebase


exports.callVision = functions.storage.object().onFinalize(async (object) => {
    // 过滤非图片、临时文件,避免无效触发
    if (!object.name || !object.contentType.startsWith('image/')) {
        return null;
    }
    const fileBucket = object.bucket;
    const filePath = object.name;
    const gcsPath = `gs://${fileBucket}/${filePath}`;

    // 新版Vision API直接传类型字符串即可,无需引用内部嵌套类型
    const req = {
      image: {source: {imageUri: gcsPath}},
      features: [
        { type: 'WEB_DETECTION' },
        { type: 'SAFE_SEARCH_DETECTION' }
      ],
    };
    console.log('开始处理图片:', gcsPath);
    try {
        const [response] = await vision.annotateImage(req);
        const visionResp = {
            web: response.webDetection,
            safe: response.safeSearchAnnotation
        };
        const db = admin.firestore();
        // 去掉路径前缀images/,和存储文件名保持一致作为文档ID
        const docId = filePath.replace(/^images\//, '');
        await db.collection('images').doc(docId).set(visionResp);
        console.log('数据写入Firestore成功,文档ID:', docId);
        return null;
    } catch (err) {
        console.error('Vision API处理失败:', err);
        throw err; // 抛出错误触发函数重试,不要静默吞错
    }
});

2. 修复Swift端逻辑问题

原代码存在两个问题:一是上传时固定文件名file.png会导致每次上传覆盖旧文件;二是监听时生成的UUID和实际上传文件名不匹配,永远拿不到结果。修复后的核心代码如下:

func retrieveAPIData(imageName: String) {
    print("开始监听分析结果,图片名:\(imageName)")
    // 用实际上传的文件名作为文档ID监听
    self.firestore.collection("images").document(imageName)
        .addSnapshotListener { documentSnapshot, error in
            if let error = error {
                print("监听出错:", error)
                return
            }
            guard let data = documentSnapshot?.data() else {
                print("文档暂未生成,等待中...")
                return
            }
            print("拿到Vision分析结果:", data)
        }
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true, completion: nil)
    guard let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
        return
    }
    guard let imageData = image.pngData() else {
        return
    }
    // 生成唯一文件名,避免覆盖旧文件
    let imageName = "\(UUID().uuidString).png"
    let imageRef = storage.child("images/\(imageName)")
    imageRef.putData(imageData, metadata: nil, completion: {_, error in
        if let error = error {
            print("图片上传失败:", error)
            return
        }
        print("图片上传成功,开始监听结果")
        // 传入实际文件名启动监听
        self.retrieveAPIData(imageName: imageName)
    })
}
部署验证步骤
  • 在云函数目录执行npm install确认所有依赖安装正确
  • 执行firebase deploy --only functions部署修复后的云函数
  • 重新运行iOS端测试,上传图片后可在云函数日志看到处理成功打印,Firestore中会生成对应文档,iOS端可正常拿到分析结果。

内容的提问来源于stack exchange,提问作者ddd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:24:25