Firebase E/StorageException:发生了 StorageException。对象在该位置不存在

Posted

技术标签:

【中文标题】Firebase E/StorageException:发生了 StorageException。对象在该位置不存在【英文标题】:Firebase E/StorageException: StorageException has occurred. Object does not exist at location 【发布时间】:2021-12-29 15:51:46 【问题描述】:

我正在尝试将 4 个不同的图像上传到 firebase 存储,我的代码适用于单个图像,但每当我尝试上传多个图像时,我都会得到

 E/StorageException: StorageException has occurred.
    Object does not exist at location.
     Code: -13010 HttpResult: 404
2021-11-18 22:45:16.584 com.example.test E/StorageException:   "error":     "code": 404,    "message": "Not Found."  
    java.io.IOException:   "error":     "code": 404,    "message": "Not Found."  
        at com.google.firebase.storage.network.NetworkRequest.parseResponse(NetworkRequest.java:445)
        at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(NetworkRequest.java:462)
        at com.google.firebase.storage.network.NetworkRequest.processResponseStream(NetworkRequest.java:453)
        at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:272)
        at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:289)
        at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:76)
        at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:68)
        at com.google.firebase.storage.GetDownloadUrlTask.run(GetDownloadUrlTask.java:77)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)

这是我将图像上传到 Firebase 存储的代码,即使出现错误,我也可以在 firebase 存储上看到图像,但我在应用程序上遇到错误。

private synchronized void UploadToFireBaseStorage(ArrayList<String> filePath,int type) 
        
        final ArrayList<String> multipleImages = new ArrayList<>();
        Log.d(TAG,"Size of File at Upload Method "+filePath.size());

        if (filePath.size()==0)
            return;
        

        
        Uri fileUri = null;

        for (String s : filePath) 
            if (s.contains(".jpg")) 
                    fileUri = Uri.fromFile(new File(s));
                 else 
                    fileUri = Uri.parse(s);
                

            
            StorageReference mStorageReference = FirebaseStorage.getInstance().getReference();
            Log.d(TAG, "UploadToFireBaseStorage: StorageRef "+mStorageReference);

           
            storageReference = mStorageReference.child("Photos").child(fileUri.getLastPathSegment());
           
            Log.d(TAG, "UploadToFireBaseStorage: Storage Reference "+storageReference);
            Log.d(TAG, "UploadToFireBaseStorage: File URI = "+fileUri);
            String finalAttachmentType = attachmentType;
            String finalUploadFolder = uploadFolder;
            storageReference.putFile(fileUri).addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() 
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) 

                    storageReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() 
                        @Override
                        public void onSuccess(@NonNull Uri uri) 
                            Log.d(TAG, "Image Uploaded ");
                            Log.d(TAG, "onSuccess: URI Uploaded == "+uri);
                            
                        
                    );
                
            ).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() 
                @Override
                public void onProgress(UploadTask.TaskSnapshot taskSnapshot) 
                    double progress = 100.0 * taskSnapshot.getBytesTransferred() / (double) taskSnapshot.getTotalByteCount();
                    Log.d(TAG, "Upload is " + progress + "% done");
                    

                
            ).addOnFailureListener(new OnFailureListener() 
                @Override
                public void onFailure(@NonNull Exception e) 
                    Log.d(TAG, "onFailure: "+s);
                    
                
            );
        
        Log.d(TAG,"Image List "+multipleImages.toString());
    

这些是我为 4 个不同图像获得的存储参考

Storage Reference gs://example-89902.appspot.com/Photos/Image%20IMG_1637256617899.jpg

Storage Reference gs://example-89902.appspot.com/Photos/Image%20IMG_1637256617949.jpg

Storage Reference gs://example-89902.appspot.com/Photos/Image%20IMG_1637256618132.jpg

Storage Reference gs://example-89902.appspot.com/Photos/Image%20IMG_1637256618070.jpg

Firebase 存储规则:

Firebase Storage Rules
service firebase.storage 
  match /b/bucket/o 
    match /allPaths=** 
      allow read, write;
    
  

【问题讨论】:

Log.d(TAG, "onSuccess: URI Uploaded == "+uri); 是否记录正确的 URI? @AlexMamo 如果我上传 4,那么它会显示 2 张图像,而对于其他 2,它只会显示我上面提到的错误 我认为answer 会有所帮助。是吗? @AlexMamo 感谢您的建议,但我的方法是synchronized 有效吗?或者如果没有,那么关于如何同步上传过程的任何建议? @AlexMamo 我对上传顺序没有任何问题,您还可以看到,当我上传成功时,我只对图像做一些事情。你能帮帮我吗? 【参考方案1】:

根据堆栈跟踪,问题似乎与获取下载网址有关:

at com.google.firebase.storage.GetDownloadUrlTask.run(GetDownloadUrlTask.java:77)

可能是这段代码造成的:

@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) 

  storageReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() 
      @Override
      public void onSuccess(@NonNull Uri uri) 
          Log.d(TAG, "Image Uploaded ");
          Log.d(TAG, "onSuccess: URI Uploaded == "+uri);
          
      
  );
  

我的猜测是上传成功回调与存储引用和相应下载 url 可用的时刻之间存在某种竞争条件。

请按照Firebase documentation中的建议,尝试修改您的代码以获得下载地址:

private synchronized void UploadToFireBaseStorage(ArrayList<String> filePath,int type) 
        
    final ArrayList<String> multipleImages = new ArrayList<>();
    Log.d(TAG,"Size of File at Upload Method "+filePath.size());

    if (filePath.size()==0)
        return;
    

    
    Uri fileUri = null;

    for (String s : filePath) 
        if (s.contains(".jpg")) 
                fileUri = Uri.fromFile(new File(s));
             else 
                fileUri = Uri.parse(s);
            

        
        StorageReference mStorageReference = FirebaseStorage.getInstance().getReference();
        Log.d(TAG, "UploadToFireBaseStorage: StorageRef "+mStorageReference);

        
        storageReference = mStorageReference.child("Photos").child(fileUri.getLastPathSegment());
        
        Log.d(TAG, "UploadToFireBaseStorage: Storage Reference "+storageReference);
        Log.d(TAG, "UploadToFireBaseStorage: File URI = "+fileUri);
        String finalAttachmentType = attachmentType;
        String finalUploadFolder = uploadFolder;
        UploadTask uploadTask = storageReference.putFile(fileUri).addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() 
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) 
                // The stuff you considerd appropriate
                Log.d(TAG, "Image Uploaded ");
            
        ).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() 
            @Override
            public void onProgress(UploadTask.TaskSnapshot taskSnapshot) 
                double progress = 100.0 * taskSnapshot.getBytesTransferred() / (double) taskSnapshot.getTotalByteCount();
                Log.d(TAG, "Upload is " + progress + "% done");
                

            
        ).addOnFailureListener(new OnFailureListener() 
            @Override
            public void onFailure(@NonNull Exception e) 
                Log.d(TAG, "onFailure: "+s);
                
            
        );

        uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() 
            @Override
            public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception 
                if (!task.isSuccessful()) 
                    throw task.getException();
                

                // Continue with the task to get the download URL
                return ref.getDownloadUrl();
            
        ).addOnCompleteListener(new OnCompleteListener<Uri>() 
            @Override
            public void onComplete(@NonNull Task<Uri> task) 
                if (task.isSuccessful()) 
                    Uri downloadUri = task.getResult();
                    Log.d(TAG, "onSuccess: URI Uploaded == "+downloadUri);
                 else 
                    // Handle failures
                    // ...
                
            
        );
    
    Log.d(TAG,"Image List "+multipleImages.toString());

以前UploadTask.TaskSnapshot 有一个getDownloadUrl() 方法,但它不再可用。例如,this one 等不同的问题已经讨论了这个主题,它也提供了更多的替代方案。


作为旁注,您在 cmets 中指出其中两个图像已成功上传,而另外两个未成功上传,并且可能不相关,但肯定很好奇。正如您在source code of Uploadtask 中看到的那样,此类任务是使用以下代码安排的:

@Override
protected void schedule() 
  StorageTaskScheduler.getInstance().scheduleUpload(getRunnable());

StorageTaskScheduler 在最多两个线程的线程池执行器中调度上传:

private static final ThreadPoolExecutor UPLOAD_QUEUE_EXECUTOR =
    new ThreadPoolExecutor(
        2, 2, 5, TimeUnit.SECONDS, mUploadQueue, new StorageThreadFactory("Upload-"));

当您尝试上传比可用线程数更多的图像时,此线程池可能会阻止某些上传。

相比之下,获取下载url的操作是在不同的thread pool中进行的:

private static final ThreadPoolExecutor COMMAND_POOL_EXECUTOR =
    new ThreadPoolExecutor(
        5, 5, 5, TimeUnit.SECONDS, mCommandQueue, new StorageThreadFactory("Command-"));

如您所见,在这个池中线程数为 5,这意味着有足够的空间来提交 get 下载任务操作。

我查看了代码,没有发现任何泄漏,但可以肯定的是,这种差异可能与您的问题有任何关系。

【讨论】:

感谢您的回答。如前所述,我尝试了文档中的代码,但我仍然收到与问题中相同的“找不到对象错误” 欢迎您@androidXP。非常感谢您的反馈。这确实很奇怪。您是否从UploadTask OnSuccessListener 回调中删除了代码片段storageReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener&lt;Uri&gt;() @Override public void onSuccess(@NonNull Uri uri) Log.d(TAG, "Image Uploaded "); Log.d(TAG, "onSuccess: URI Uploaded == "+uri); );?即使这样,错误仍然存​​在? 是的,在addOnCompleteListenertask.isSuccessful() 是错误的 2 次,当我一起上传 4 张图像时,是正确的 2 次。然后它给了我上面提到的同样的错误。 但是我可以检查你提到的代码也是官方代码,但是你从 github 提到的另一个链接有一些我试过的代码,奇怪的是这个代码 @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) Task&lt;Uri&gt; urlTask = taskSnapshot.getStorage().getDownloadUrl(); while (!urlTask.isSuccessful()); Uri downloadUrl = urlTask.getResult(); FriendlyMessage friendlyMessage = new FriendlyMessage(null, mUsername, downloadUrl.toString()); mDatabaseReference.push().setValue(friendlyMessage); 工作得很好。你能解释一下为什么吗? while (!urlTask.isSuccessful()); 的作用不是if else

以上是关于Firebase E/StorageException:发生了 StorageException。对象在该位置不存在的主要内容,如果未能解决你的问题,请参考以下文章

无法解决:com.google.firebase:firebase-ml-vision:24.1.3;无法解决:com.google.firebase:firebase-core:20.0.2

没有创建 Firebase 应用“[DEFAULT]” - 在 Flutter 和 Firebase 中调用 Firebase.initializeApp()

如何修复 Firebase 9.0 导入错误? “尝试导入错误:‘firebase/app’不包含默认导出(导入为‘firebase’)。”

Firebase 持久化,清除 Firebase 缓存

Firebase 存储不会下载并添加到 firebase 数据库

将 Firebase 身份验证与 Firebase 数据库连接