如何将一个base64图像URL上传到Firebase并检索其访问令牌?

huangapple go评论73阅读模式
英文:

How to upload a base64 image URL to Firebase and retrieve its access token?

问题

在一个MERN + Firebase项目中,我有一个图像数据字符串,我想要上传它,然后获取该文件的访问令牌。

图像数据字符串的格式如下:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOoAAAClCAYAAABSmmH3AAAAAXNSR0IArs4c6QAABFJJREFUeF7t1oENg0AQA8F8/6XSAx8pVWTloQIzZwvOvfd+PAQI/LXAMdS/vo9wBH4ChqoIBAIChho4kogEDFUHCAQEDDVwJBEJGKoOEAgIGGrgSCISMFQdIBAQMNTAkUQkYKg6QCAgYKiBI4lIwFB1gEBAwFADRxKRgKHqAIGAgKEGjiQiAUPVAQIBAUMNHElEAoaqAwQCAoYaOJKIBAxVBwgEBAw1cCQRCRiqDhAICBhq4EgiEjBUHSAQEDDUwJFEJGCoOkAgIGCogSOJSMBQdYBAQMBQA0cSkYCh6gCBgIChBo4kIgFD1QECAQFDDRxJRAKGqgMEAgKGGjiSiAQMVQcIBAQMNXAkEQkYqg4QCAgYauBIIhIwVB0gEBAw1MCRRCRgqDpAICBgqIEjiUjAUHWAQEDAUANHEpGAoeoAgYCAoQaOJCIBQ9UBAgEBQw0cSUQChqoDBAIChho4kogEDFUHCAQEDDVwJBEJGKoOEAgIGGrgSCISMFQdIBAQMNTAkUQkYKg6QCAgYKiBI4lIwFB1gEBAwFADRxKRgKHqAIGAgKEGjiQiAUPVAQIBAUMNHElEAoaqAwQCAoYaOJKIBAxVBwgEBAw1cCQRCRiqDhAICBhq4EgiEjBUHSAQEDDUwJFEJGCoOkAgIGCogSOJSMBQdYBAQMBQA0cSkYCh6gCBgIChBo4kIgFD1QECAQFDDRxJRAKGqgMEAgKGGjiSiAQMVQcIBAQMNXAkEQkYqg4QCAgYauBIIhIwVB0gEBAw1MCRRCRgqDpAICBgqIEjiUjAUHWAQEDAUANHEpGAoeoAgYCAoQaOJCIBQ9UBAgGB8zzPDeQUkcC0wHnf11CnK+DlCwJ+fQtXknFewBd1vgIACgK+qIUryTgvYKjzFQBQEDDUwpVknBcw1PkKACgIGGrhSjLOCxjqfAUAFAQMtXAlGecFDHW+AgAKAoZauJKM8wKGOl8BAAUBQy1cScZ5AUOdrwCAgoChFq4k47yAoc5XAEBBwFALV5JxXsBQ5ysAoCBgqIUryTgvYKjzFQBQEDDUwpVknBcw1PkKACgIGGrhSjLOCxjqfAUAFAQMtXAlGecFDHW+AgAKAoZauJKM8wKGOl8BAAUBQy1cScZ5AUOdrwCAgoChFq4k47yAoc5XAEBBwFALV5JxXsBQ5ysAoCBgqIUryTgvYKjzFQBQEDDUwpVknBcw1PkKACgIGGrhSjLOCxjqfAUAFAQMtXAlGecFDHW+AgAKAoZauJKM8wKGOl8BAAUBQy1cScZ5AUOdrwCAgoChFq4k47yAoc5XAEBBwFALV5JxXsBQ5ysAoCDwBaT9ke70WG4vAAAAAElFTkSuQmCC

这是文件应该上传的参考位置:

const imageRef: StorageReference = ref(
  storage,
  `/issueImages/${firebaseImageId}`
);

到目前为止,我已经尝试使用put函数与imageRef,当我尝试使用firebase的uploadBytes()时,我必须将其上传为Buffer,即使这样,我仍然无法在元数据中找到访问令牌。

英文:

In a MERN + Firebase project, I have an image data string that I want to upload and then get the access token of that file.

The image data string is of the following form:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOoAAAClCAYAAABSmmH3AAAAAXNSR0IArs4c6QAABFJJREFUeF7t1oENg0AQA8F8/6XSAx8pVWTloQIzZwvOvfd+PAQI/LXAMdS/vo9wBH4ChqoIBAIChho4kogEDFUHCAQEDDVwJBEJGKoOEAgIGGrgSCISMFQdIBAQMNTAkUQkYKg6QCAgYKiBI4lIwFB1gEBAwFADRxKRgKHqAIGAgKEGjiQiAUPVAQIBAUMNHElEAoaqAwQCAoYaOJKIBAxVBwgEBAw1cCQRCRiqDhAICBhq4EgiEjBUHSAQEDDUwJFEJGCoOkAgIGCogSOJSMBQdYBAQMBQA0cSkYCh6gCBgIChBo4kIgFD1QECAQFDDRxJRAKGqgMEAgKGGjiSiAQMVQcIBAQMNXAkEQkYqg4QCAgYauBIIhIwVB0gEBAw1MCRRCRgqDpAICBgqIEjiUjAUHWAQEDAUANHEpGAoeoAgYCAoQaOJCIBQ9UBAgEBQw0cSUQChqoDBAIChho4kogEDFUHCAQEDDVwJBEJGKoOEAgIGGrgSCISMFQdIBAQMNTAkUQkYKg6QCAgYKiBI4lIwFB1gEBAwFADRxKRgKHqAIGAgKEGjiQiAUPVAQIBAUMNHElEAoaqAwQCAoYaOJKIBAxVBwgEBAw1cCQRCRiqDhAICBhq4EgiEjBUHSAQEDDUwJFEJGCoOkAgIGCogSOJSMBQdYBAQMBQA0cSkYCh6gCBgIChBo4kIgFD1QECAQFDDRxJRAKGqgMEAgKGGjiSiAQMVQcIBAQMNXAkEQkYqg4QCAgYauBIIhIwVB0gEBAw1MCRRCRgqDpAICBgqIEjiUjAUHWAQEDAUANHEpGAoeoAgYCAoQaOJCIBQ9UBAgGB8zzPDeQUkcC0wHnf11CnK+DlCwJ+fQtXknFewBd1vgIACgK+qIUryTgvYKjzFQBQEDDUwpVknBcw1PkKACgIGGrhSjLOCxjqfAUAFAQMtXAlGecFDHW+AgAKAoZauJKM8wKGOl8BAAUBQy1cScZ5AUOdrwCAgoChFq4k47yAoc5XAEBBwFALV5JxXsBQ5ysAoCBgqIUryTgvYKjzFQBQEDDUwpVknBcw1PkKACgIGGrhSjLOCxjqfAUAFAQMtXAlGecFDHW+AgAKAoZauJKM8wKGOl8BAAUBQy1cScZ5AUOdrwCAgoChFq4k47yAoc5XAEBBwFALV5JxXsBQ5ysAoCBgqIUryTgvYKjzFQBQEDDUwpVknBcw1PkKACgIGGrhSjLOCxjqfAUAFAQMtXAlGecFDHW+AgAKAoZauJKM8wKGOl8BAAUBQy1cScZ5AUOdrwCAgoChFq4k47yAoc5XAEBBwFALV5JxXsBQ5ysAoCBgqIUryTgvYKjzFQBQEDDUwpVknBcw1PkKACgIGGrhSjLOCxjqfAUAFAQMtXAlGecFDHW+AgAKAoZauJKM8wKGOl8BAAUBQy1cScZ5AUOdrwCAgoChFq4k47yAoc5XAEBBwFALV5JxXsBQ5ysAoCDwBaT9ke70WG4vAAAAAElFTkSuQmCC

This is the reference to where the file should be uploaded:

const imageRef: StorageReference = ref(
  storage,
  `/issueImages/${firebaseImageId}`
);

So far, I have attempted to use the 'put' function with the imageRef, and when I try using uploadBytes() of firebase, I have to upload it as a Buffer, and even then I cannot seem to find the access token in the metadata.

答案1

得分: 1

要将数据URL上传到Firebase,您将使用以下代码(取决于您使用的SDK):

在Cloud Storage存储桶中上传文件后,只有在客户端调用其版本的getDownloadURL()后,该文件才会被分配访问令牌。因此,为了解决您的问题,您应该在上传后立即调用getDownloadURL()

如果Node.js在客户端的计算机上运行,您可以使用以下代码:

// 旧版语法
import * as firebase from "firebase";

// 文件引用
const imageStorageRef = firebase.storage()
  .ref(`/issueImages/${firebaseImageId}`);

// 执行上传
await imageStorageRef.putString(dataUrl, 'DATA_URL');

// 获取下载URL
const imageStorageDownloadURL = await imageStorageRef.getDownloadURL();
// 现代语法
import { getStorage, getDownloadURL, ref, uploadString } from "firebase/storage";

// 文件引用
const imageStorageRef = ref(
  getStorage(),
  `/issueImages/${firebaseImageId}`
);

// 执行上传
await uploadString(imageStorageRef, dataUrl, 'DATA_URL');

// 获取下载URL
const imageStorageDownloadURL = await getDownloadURL(imageStorageRef);

如果Node.js运行在您控制的私有服务器上,您应该选择使用Firebase Admin SDK,因为它可以绕过客户端SDK所应用的速率限制和限制。

如前所述,下载URL不会自动创建。不幸的是,getDownloadURL是客户端SDK的功能,而Admin SDK没有此功能。因此,我们可以让客户端在需要时调用getDownloadURL,或者如果想要将其插入到数据库中,我们可以手动创建下载URL。

Nico这篇关于Firebase存储URL工作原理的文章中提供了关于如何创建(或重新创建)上传后的下载URL的详细信息,他在这篇文章中整理了来自Firebase扩展GitHub这个StackOverflow帖子的信息。总之,要在上传后创建(或重新创建)下载URL,您可以使用以下函数:

import { uuid } from "uuidv4";

// 原始来源:Nico (@nicomqh)
// https://www.sentinelstand.com/article/guide-to-firebase-storage-download-urls-tokens
// “file”是来自Cloud Storage SDK的File类的实例
// 多次执行此函数将撤销所有先前的令牌
function createDownloadURL(file) {
  const downloadToken = uuid();

  await file.setMetadata({
    metadata: {
      firebaseStorageDownloadTokens: downloadToken
    }
  });

  return `https://firebasestorage.googleapis.com/v0/b/${file.bucket.name}/o/${encodeURIComponent(file.name)}?alt=media&token=${downloadToken}`;
}

这使我们可以将上面的客户端代码更改为以下Admin SDK版本:

// 假设已经初始化firebase-admin
import { getStorage } from "firebase-admin/storage";

// 文件引用
const imageStorageFile = getStorage()
  .bucket()
  .file(`/issueImages/${firebaseImageId}`);

// 执行上传
await imageStorageFile.save(dataUrl);

// 获取下载URL
const imageStorageDownloadURL = await createDownloadURL(imageStorageFile);

在所有上述示例中,下载URL都被提取并保存在imageStorageDownloadURL变量中。您应该将此值原样存储在数据库中。但是,如果您希望仅存储访问令牌并根据需要重新组装URL,您可以使用以下代码从其?token=参数中提取令牌:

const downloadToken = new URL(imageStorageDownloadURL).searchParams.get('token');
英文:

To upload a data URL to Firebase, you would use storageRef.putString(url, 'DATA_URL') (legacy) or uploadString(storageRef, url, 'DATA_URL') (modern) depending on the SDK you are using.

When you upload a file to a Cloud Storage bucket, it will not be issued an access token until a client calls its version of getDownloadURL(). So to fix your issue, you would call getDownloadURL() immediately after upload.

If Node is running on a client's machine, you would use:

// legacy syntax
import * as firebase from "firebase";

// reference to file
const imageStorageRef = firebase.storage()
  .ref(`/issueImages/${firebaseImageId}`);

// perform the upload
await imageStorageRef.putString(dataUrl, 'DATA_URL');

// get the download URL
const imageStorageDownloadURL = await imageStorageRef.getDownloadURL();
// modern syntax
import { getStorage, getDownloadURL, ref, uploadString } from "firebase/storage";

// reference to file
const imageStorageRef = ref(
  getStorage(),
  `/issueImages/${firebaseImageId}`
);

// perform the upload
await uploadString(imageStorageRef, dataUrl, 'DATA_URL');

// get the download URL
const imageStorageDownloadURL = await getDownloadURL(imageStorageRef);

If Node is running on a private server you control, you should opt to use the Firebase Admin SDK instead as it bypasses the rate limits and restrictions applied to the client SDKs.

As mentioned before, the download URLs aren't created automatically. Unfortunately for us, getDownloadURL is a feature of the client SDKs and the Admin SDK doesn't have it. So we can either let a client call getDownloadURL when it is needed or we can manually create the download URL if we want to insert it into a database.

Nico has an excellent write up on how Firebase Storage URLs work, where they collated information from the Firebase Extensions GitHub and this StackOverflow thread. In summary, to create (or recreate) a download URL once it has been uploaded, you can use the following function:

import { uuid } from "uuidv4";

// Original Credit: Nico (@nicomqh)
// https://www.sentinelstand.com/article/guide-to-firebase-storage-download-urls-tokens
// "file" is an instance of the File class from the Cloud Storage SDK
// executing this function more than once will revoke all previous tokens
function createDownloadURL(file) {
  const downloadToken = uuid();

  await file.setMetadata({
    metadata: {
      firebaseStorageDownloadTokens: downloadToken
    }
  });

  return `https://firebasestorage.googleapis.com/v0/b/${file.bucket.name}/o/${encodeURIComponent(file.name)}?alt=media&token=${downloadToken}`;
}

The allows us to change the client-side code above into the following so it can run using the Admin SDK:

// assuming firebase-admin is initialized already
import { getStorage } from "firebase-admin/storage";

// reference to file
const imageStorageFile = getStorage()
  .bucket()
  .file(`/issueImages/${firebaseImageId}`);

// perform the upload
await imageStorageFile.save(dataUrl);

// get the download URL
const imageStorageDownloadURL = await createDownloadURL(imageStorageFile);

In all of the above examples, a download URL is retrieved and saved to the imageStorageDownloadURL variable. You should store this value as-is in your database. However, if you instead want to store only the access token and reassemble the URL on an as-needed basis, you can extract the token from its ?token= parameter using:

const downloadToken = new URL(imageStorageDownloadURL).searchParams.get('token');

huangapple
  • 本文由 发表于 2023年1月8日 20:48:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75047876.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定