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

Firebase存储上传头像报[object-not-found]错误求助

Firebase Storage 头像上传报错排查:[firebase_storage/object-not-found]

问题说明

开发注册用户头像上传功能,计划将头像存储至Firebase,但在ProfilePage页面出现如下报错:

Error uploading profile picture: [firebase_storage/object-not-found] No object exists at the desired reference

已确认直接操作Firebase集合功能正常,尝试过其他帖子提供的解决方法但未解决问题,相关Flutter代码如下:

imported files here 

class ProfilePage extends StatefulWidget {
  @override
  _ProfilePageState createState() => _ProfilePageState();
}

class _ProfilePageState extends State<ProfilePage> {
  final User? user = FirebaseAuth.instance.currentUser;
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;
  File? _imageFile;
  String? _profileImageUrl;
  
  @override
  void initState() {
    super.initState();
    _loadProfileImage();
  }

  Future<void> _loadProfileImage() async {
    if (user != null) {
      DocumentSnapshot userDoc = await _firestore.collection('users').doc(user!.uid).get();
      if (userDoc.exists && userDoc.data() != null) {
        setState(() {
          _profileImageUrl = userDoc['profilePic'];
        });
      }
    }
  }

  Future<void> _pickImage() async {
    final pickedFile = await ImagePicker().getImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      setState(() {
        _imageFile = File(pickedFile.path);
      });
      _uploadImage(_imageFile!);
    }
  }

  Future<void> _uploadImage(File imageFile) async {
    try {
      String fileName = path.basename(imageFile.path);
      Reference storageRef = FirebaseStorage.instance.ref().child('profile_pics/$fileName');
      final UploadTask uploadTask = storageRef.putFile(imageFile);
      final TaskSnapshot snapshot = await uploadTask.whenComplete(() => {});
      final String downloadUrl = await snapshot.ref.getDownloadURL();

      SharedPreferences prefs = await SharedPreferences.getInstance();
      String? userId = prefs.getString('userId');

      if (userId != null) {
        await FirebaseFirestore.instance.collection('users').doc(userId).update({
          'profilePic': downloadUrl,
        });

        setState(() {
          _profileImageUrl = downloadUrl;
        });

        print('Profile picture uploaded successfully: $downloadUrl');
      } else {
        print('User ID not found in SharedPreferences');
      }
    } catch (e) {
      print('Error uploading profile picture: $e');
    }
  }

  Future<void> _signOut(BuildContext context) async {
    await FirebaseAuth.instance.signOut();
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.remove('staySignedIn');
    await prefs.remove('email');
    await prefs.remove('password');
    Navigator.pushAndRemoveUntil(
      context,
      MaterialPageRoute(builder: (context) => LoginPage()),
      (Route<dynamic> route) => false,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(user?.displayName ?? 'Profile'),
        actions: [
          IconButton(
            icon: Icon(Icons.logout),
            onPressed: () => _signOut(context),
          ),
        ],
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              GestureDetector(
                onTap: _pickImage,
                child: CircleAvatar(
                  radius: 50,
                  backgroundImage: _imageFile != null
                      ? FileImage(_imageFile!)
                      : _profileImageUrl != null
                          ? NetworkImage(_profileImageUrl!) as ImageProvider
                          : null,
                  child: _imageFile == null && _profileImageUrl == null
                      ? Icon(Icons.add_a_photo, size: 50)
                      : null,
                ),
              ),
              SizedBox(height: 20),
              Text(
                user?.displayName ?? 'No Name',
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

排查与解决方法

1. 检查Firebase Storage权限与路径

  • 确认Firebase Storage规则允许当前认证用户写入profile_pics目录,修改规则为:
    rules_version = '2';
    service firebase.storage {
      match /b/{bucket}/o {
        match /profile_pics/{allPaths=**} {
          allow read, write: if request.auth != null;
        }
      }
    }
    
  • 避免重复文件名导致的覆盖或路径问题,建议用用户UID作为唯一文件名:
    // 在_uploadImage中替换fileName逻辑
    String fileName = '${user!.uid}.jpg';
    

2. 修复UploadTask完成后的引用逻辑

原代码中whenComplete的写法可能导致快照状态未正确确认,修改为直接等待任务完成并校验状态:

final TaskSnapshot snapshot = await uploadTask;
if (snapshot.state == TaskState.success) {
  final String downloadUrl = await snapshot.ref.getDownloadURL();
  // 后续更新Firestore的逻辑
} else {
  print('上传失败,状态:${snapshot.state}');
}

3. 统一用户ID来源

代码中加载头像用的是FirebaseAuth.instance.currentUser!.uid,但上传时用的是SharedPreferences中的userId,两者可能不一致。统一使用当前认证用户的UID:

// 在_uploadImage中替换userId相关逻辑
if (user != null) {
  await FirebaseFirestore.instance.collection('users').doc(user!.uid).update({
    'profilePic': downloadUrl,
  });
  setState(() {
    _profileImageUrl = downloadUrl;
  });
  print('Profile picture uploaded successfully: $downloadUrl');
} else {
  print('用户未登录');
}

4. 适配ImagePicker最新版本

如果使用的是最新版image_picker(>=0.8.0),getImage已被弃用,改用pickImage并直接获取文件名:

Future<void> _pickImage() async {
  final XFile? pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
  if (pickedFile != null) {
    setState(() {
      _imageFile = File(pickedFile.path);
    });
    // 直接用XFile的name属性作为文件名
    _uploadImage(_imageFile!, pickedFile.name);
  }
}

// 调整_uploadImage方法参数
Future<void> _uploadImage(File imageFile, String fileName) async {
  try {
    Reference storageRef = FirebaseStorage.instance.ref().child('profile_pics/$fileName');
    // ... 剩余逻辑
  } catch (e) {
    print('Error uploading profile picture: $e');
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:05:54