【问题标题】:Ways to access firebase storage (photos) via web app通过网络应用访问 Firebase 存储(照片)的方法
【发布时间】:2018-07-12 06:50:11
【问题描述】:

我对使用 react redux firebase Web 应用访问存储在 Firebase 存储中的一堆图像的适当方式感到困惑。简而言之,我很想了解一下,一旦将照片上传到 Firebase 存储,您将如何将其链接到 Firebase 数据库(就像您要存储的快照返回的确切内容一样),然后访问它(如果它不只是<img src={data.downloadURL} />),以及当照片被覆盖时您将如何处理(如有必要)更新该链接。 如果你能回答这个问题,请随意跳过其余部分......

我遇到的两个选项是

  1. 将完整的 URL 存储在我的 Firebase 数据库中,或者
  2. 少存储一些东西,比如存储桶中的路径,然后为每张照片调用 downloadURL()...这似乎有很多不必要的流量,不是吗?

我现在的数据库结构是这样的:

{
  <someProjectId>:  {
    imgs: {
      <someAutoGenId>: {
        "name":"photo1.jpg",
        "url":"https://<bucket, path, etc>token=<token>"
      },
      ...
    },
    <otherProjectDetails>: "",
    ...
  },
  ...
}

继续使用该结构和列出的第一个想法,当照片被覆盖时我遇到了麻烦,所以我需要遍历图像列表并删除与名称匹配的数据库记录(或找到它并更新它的网址)。我可以做到这一点(最多,我需要替换两个带有旧令牌的参考),但后来我看到人们通过选项 2 这样做,尽管不一定符合我的确切情况。

我最后一次看到的最后一件事是类似的问题,一般回复指向 Cloud Functions,我将在发布后立即进行调查,但我不确定这是否让我的情况过于复杂,所以我想问起来不会有太大的伤害。我最初看到/阅读了 Cloud Functions 以及 Firebase 的数据库是“实时的”这一事实,但不确定它是否在 React/Redux 环境中运行良好。无论如何,我将不胜感激,谢谢。

【问题讨论】:

  • 我忘了提到我目前正在考虑的第三个选项,即允许对 firebase 存储桶进行无限制的读取访问,然后在将 url 保存到数据库时省略令牌。最后保持“alt”变量(设置为“media”),我可以得到要渲染的图片,然后当图像被覆盖时,数据库中没有什么可以更新的。目前,这对我来说是一个可行的解决方案,但我将尝试找出一个涉及 Cloud Functions 的解决方案,因为这似乎是类似问题的首选答案。

标签: reactjs firebase-realtime-database react-redux firebase-storage google-cloud-functions


【解决方案1】:

在研究 Cloud Functions 时,我意识到使用 Cloud Functions 并不是一个完全独立的选项,而是一种完成我上面列出的第一个选项(可能也是第二个选项)的方法。我真的很想把这一点说清楚,但我很有信心我失败了……所以我很抱歉。这是我的(两部分)工作解决方案,用于将 Firebase DB 中的引用同步到 Firebase 存储 url(在 React Redux Web 应用程序中,尽管我认为第一部分无论如何都应该适用):

第一部分

点击此处https://firebase.google.com/docs/functions/get-started 启用云功能。

我存储的与图像相关的信息的数据库部分位于/projects/detail/{projectKey}/imgs,并具有以下结构:

{ <autoGenKey1>: { name: 'image1.jpg', url: <longURLWithToken> }, <moreAutoGenKeys>: { ... }, ...}

我的云函数如下所示:

exports.updateURLToken = functions.database.ref(`/projects/detail/{projectKey}/imgs`)
  .onWrite(event => {

    const projectKey = event.params.projectKey
    const newObjectSet = event.data.val()
      const newKeys = Object.keys(newObjectSet)
    const oldObjectSet = event.data.previous.val()
      const oldKeys = Object.keys(oldObjectSet)
    let newObjectKey = null

    // If something was removed, none of this is necessary - return
    if (oldKeys.length > newKeys.length) {
      return null
    }

    for (let i = 0; i < newKeys.length; ++i) {// Looking for the new object -> will be missing in oldObjectSet
      const key = newKeys[i]
      if (oldKeys.indexOf(key) === -1) {// Found new object
        newObjectKey = key
        break
      }
    }

    if (newObjectKey !== null) {// Checking if new object overwrote an existing object (same name)
      const newObject = newObjectSet[newObjectKey]
      let duplicateKey = null
      for (let i = 0; i < oldKeys.length; ++i) {
        const oldObject = oldObjectSet[oldKeys[i]]
        if (newObject.name === oldObject.name) {// Duplicate found
          duplicateKey = oldKeys[i]
          break
        }
      }

      if (duplicateKey !== null) {// Remove duplicate
        return event.data.ref.child(duplicateKey).remove((error) => error ? 'Error removing duplicate project detail image' : true)
      }
    }

    return null
  })

加载此函数后,每次在该位置发生任何更改时,它都会运行 (projects/detail/{projectKey}/imgs)。所以我上传了图片,在我的数据库中添加了一个带有名称和 url 的新对象,然后这将找到创建的新对象,如果它有重复的名称,则从数据库中删除同名的旧对象.

第二部分

所以现在我的数据库有正确的信息,但除非我在每次上传图像后刷新页面,否则将新对象添加到我的数据库会导致(本地)我仍然拥有所有重复的参考,这就是实时数据库发挥作用。

在我的容器里,我有:

function mapDispatchToProps (dispatch) {
  syncProjectDetailImages(dispatch) // the relavant line -> imported from api.js
  return bindActionCreators({
    ...projectsContentActionCreators,
    ...themeActionCreators,
    ...userActionCreators,
  }, dispatch)
}

然后我的 api.js 保存了 syncProjectDetailImages 函数:

const SAVING_PROJECT_SUCCESS = 'SAVING_PROJECT_SUCCESS'
export function syncProjectDetailImages (dispatch) {
  ref.child(`projects/detail`).on('child_changed', (snapshot) => {
    dispatch(projectDetailImagesUpdated(snapshot.key, snapshot.val()))
  })
}
function projectDetailImagesUpdated (key, updatedProject) {
  return {
    type: SAVING_PROJECT_SUCCESS,
    group: 'detail',
    key,
    updatedProject
  }
}

最后,在我的模块文件夹中找到了分派(我使用了与使用 redux 保存更新项目的任何部分时相同的功能 - 不需要新代码)

【讨论】:

    猜你喜欢
    • 2021-01-06
    • 1970-01-01
    • 2015-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-03
    • 2021-12-16
    • 1970-01-01
    相关资源
    最近更新 更多