Firebase Storage图片上传失败:代码错误与用户未认证问题解决及代码重写请求
解决Firebase Storage上传图片的两类问题
我来帮你搞定这两个上传图片时遇到的问题,咱们逐个拆解解决:
问题1:获取下载URL的API使用错误
你原来的代码里直接调用task.getResult().getDownloadUrl().toString()有两个核心问题:
- Firebase Storage的
getDownloadUrl()同步方法已经被弃用,而且它本质是异步操作,同步调用要么拿不到正确结果,要么直接抛出异常; - 语法上虽然没报错,但这种写法不符合新版Firebase的异步设计规范。
正确的做法是通过StorageReference的异步getDownloadUrl()方法,配合监听器来获取下载链接。
问题2:用户未认证的权限拦截
这个提示说明你的Firebase Storage安全规则要求必须登录用户才能上传文件(默认规则就是allow read, write: if request.auth != null;)。所以上传前必须确保用户已经通过Firebase Authentication完成登录,否则会被规则拦截。
修正后的完整代码
下面是整合了两个问题修复的代码,我加了注释标注修改点:
// 第一步:先检查用户是否已登录,从根源避免未认证错误 FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); if (currentUser == null) { // 这里可以添加引导用户登录的逻辑,比如跳转到登录页面 Toast.makeText(PostActivity.this, "请先登录账号再发布内容", Toast.LENGTH_SHORT).show(); return; } final StorageReference newPhoto = mPhotosStrorage.child(imageUri.getLastPathSegment()); newPhoto.putFile(imageUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() { @Override public void onComplete(@NonNull Task<UploadTask.TaskSnapshot> task) { if (task.isSuccessful()) { final String myKey = mPhotosDatabase.push().getKey(); // 修复:用异步方式获取下载URL(替代已弃用的同步方法) newPhoto.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public void onSuccess(Uri uri) { String download_url = uri.toString(); String datem = getDateTime(); DatabaseReference newDatabase = mPhotosDatabase.child(myKey); // 优化:用Map批量写入数据,避免创建空节点 Map<String, Object> postData = new HashMap<>(); postData.put("postid", myKey); postData.put("postedby", userId); postData.put("postedon", datem); postData.put("postdetails", post); postData.put("postlikes", 0); // 初始化为0,替代空节点 postData.put("postviews", 0); postData.put("postcomments", 0); postData.put("postimage", download_url); newDatabase.setValue(postData).addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { pb.setVisibility(View.GONE); Pair[] pairs = new Pair[1]; pairs[0] = new Pair<View, String>(homeLayout, "etTransition"); ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(PostActivity.this, pairs); startActivity(new Intent(PostActivity.this, HomeActivity.class), options.toBundle()); } else { Toast.makeText(PostActivity.this, "保存发布信息失败:" + task.getException().getMessage(), Toast.LENGTH_SHORT).show(); } } }); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(PostActivity.this, "获取图片链接失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } }); } else { Toast.makeText(PostActivity.this, "上传图片失败:" + task.getException().getMessage(), Toast.LENGTH_SHORT).show(); } } });
额外优化说明
- 把分散的
setValue()改成Map批量写入,既提升效率,又避免了原来代码中创建空节点(比如postlikes只创建节点但没赋值)的问题; - 给
getDownloadUrl()添加了失败监听,方便排查获取链接时的异常; - 在代码最开头加入用户登录检查,直接拦截未登录的上传请求,避免触发权限错误。
内容的提问来源于stack exchange,提问作者user14346592
相关产品推荐
相关产品推荐

