Android Firebase 上传图片错误 URL(问题:缺少 X-Goog-Upload-Comment header)

Android Firebase uploading images wrong URL (PROBLEM: X-Goog-Upload-Comment header is missing)

我正在尝试从具有 URL link 的 Firabase 数据库上传和下载图像到 Firebase 存储。问题是奇怪的 URL 被保存到数据库(见底部的 link)。我应该怎么做才能获得正常的 URL,我可以使用它来将图像下载到我的 Android 应用程序中?提前致谢!

我在这里 post 我使用的一些代码:

上传到 Firebase 数据库和存储:

mStorageRef = FirebaseStorage.getInstance().getReference();
mDataBaseRef = FirebaseDatabase.getInstance().getReference();

if (mImageUri != null)
{
    final StorageReference fileReference = mStorageRef.child(nameimage + "." + getFileExtension(mImageUri));

    fileReference.putFile(mImageUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {

            Toast.makeText(AddAdvertisement.this, "Upload successful!", Toast.LENGTH_LONG).show();

            Upload upload = new Upload(et_localization, taskSnapshot.getUploadSessionUri().toString());
            String uploadId = mDataBaseRef.push().getKey();
            mDataBaseRef.child(uploadId).setValue(upload);


        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Toast.makeText(AddAdvertisement.this, e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });

并从 Firebase 下载:

databaseReference = FirebaseDatabase.getInstance().getReference();

databaseReference.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

        for (DataSnapshot postSnapshot : dataSnapshot.getChildren())
        {
            Upload upload = postSnapshot.getValue(Upload.class);
            mUploads.add(upload);
        }

        mAdapter = new AdverisementAdapter(getContext(),mUploads);
        mrecyclerView.setAdapter(mAdapter);
    }

和毕加索要检索图像:

@Override
public void onBindViewHolder(@NonNull ImageViewHolder imageViewHolder, int i) {

    Upload uploadCurrent = mUploads.get(i);

    imageViewHolder.textViewName.setText(uploadCurrent.getName());

    Picasso.get().load(uploadCurrent.getUrl()).into(imageViewHolder.imageView);
}

Picasso 工作正常,因为除了形成图像外,我还从 Firebase 字符串中获得了名称,该名称已正确下载。所以,我认为问题就出在这个错误 url:

https://firebasestorage.googleapis.com/v0/b/my_name/o?name=image.jpg&uploadType=resumable&upload_id=AEnB2UrrOhqOVqTHuRRVRmlkf4Gh6y5xd_w5IvRok1SNVOMNnz34dqWFJ5_lPD0DNJr05mrHrT8g97sy0d4BZAdiB6v7skkLSQ&upload_protocol=resumable

当我尝试输入这个 link 时,我收到这样的错误:

请求无效。 X-Goog-Upload-Command header 缺失。

根据关于 UploadTask.TaskSnapshot 的 getUploadSessionUri() 方法的官方文档:

Returns the session Uri, valid for approximately one week, which can be used to resume an upload later by passing this value into putFile(Uri, StorageMetadata, Uri).

恐怕这不是您要找的Uri。要获得正确的 uri,请从 post.

中查看我的回答

您正在将此值写入数据库:

taskSnapshot.getUploadSessionUri().toString()

这是上传会话的 URI,如果上传被中止,您可以使用它来恢复上传。

由于您想存储下载内容 URL,此调用对您来说毫无用处。相反,您应该调用 getDownloadUrl() 以(异步地)获取新上传文件的下载 URL:

fileReference.putFile(mImageUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {

        Toast.makeText(AddAdvertisement.this, "Upload successful!", Toast.LENGTH_LONG).show();

        fileReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
            @Override
            public void onSuccess(Uri uri) {
                String url = uri.toString();
                Upload upload = new Upload(et_localization, url);
                String uploadId = mDataBaseRef.push().getKey();
                mDataBaseRef.child(uploadId).setValue(upload);
            }
        });

    }
})...

请注意,这在 Firebase documentation on getting a download URL after uploading a file 中有很好的描述,该事件包括一个通过使用 continueWithTask 而不是嵌套回调(我在上面所做的)来完成相同的示例。

这对我不起作用(使用 Expo),但使用 XMLHttpRequest 可以。我在这里找到了这个解决方案:https://github.com/expo/expo/issues/2402#issuecomment-443726662

下面是我的代码,希望对您有所帮助。

_uploadImageAsync = async (uri) => {
  try {
    const blob = await new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.onload = function () {
        resolve(xhr.response);
      };
      xhr.onerror = function (e) {
        console.log(e);
        reject(new TypeError('Network request failed'));
      };
      xhr.responseType = 'blob';
      xhr.open('GET', uri, true);
      xhr.send(null);
    });

    const ref = firebase
      .storage()
      .ref()
      .child('images/usersPicture/test');
    const snapshot = await ref.put(blob);

    blob.close();

    return await snapshot.ref.getDownloadURL();
  } catch(error) {
    console.log(error)
  }
}
fileReference.putFile(mImageUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {

        Toast.makeText(AddAdvertisement.this, "Upload successful!", Toast.LENGTH_LONG).show();

        fileReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
            @Override
            public void onSuccess(Uri uri) {
                
               // just do your task //like hashmaps to put in

            }
        });

    }
})