获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

保存数据

保存数据的方法

将数据写入或替换到定义的路径,例如fireblog/users/user1/<data>
修补在不替换所有数据的情况下更新定义路径的一些键。
邮政添加到我们的 Firebase 数据库中的数据列表。每次我们发送POST请求时,Firebase 客户端都会生成一个唯一键,例如fireblog/users/<unique-id>/<data>
删除从指定的 Firebase 数据库引用中移除数据。

使用 PUT 写入数据

通过 REST API 的基本写入操作是PUT 。为了演示保存数据,我们将构建一个包含帖子和用户的博客应用程序。我们应用程序的所有数据都将存储在“fireblog”路径下,Firebase 数据库 URL 为“https://docs-examples.firebaseio.com/fireblog”。

让我们首先将一些用户数据保存到我们的 Firebase 数据库中。我们将通过唯一的用户名存储每个用户,我们还将存储他们的全名和出生日期。因为每个用户都有一个唯一的用户名,所以在这里使用PUT而不是POST是有意义的,因为我们已经有了密钥并且不需要创建一个。

使用PUT ,我们可以将字符串、数字、布尔值、数组或任何 JSON 对象写入 Firebase 数据库。在这种情况下,我们将传递一个对象:

curl -X PUT -d '{
  "alanisawesome": {
    "name": "Alan Turing",
    "birthday": "June 23, 1912"
  }
}' 'https://docs-examples.firebaseio.com/fireblog/users.json'

将 JSON 对象保存到数据库时,对象属性会自动以嵌套方式映射到子位置。如果我们导航到新创建的节点,我们将看到值“Alan Turing”。我们还可以将数据直接保存到子位置:

curl -X PUT -d '"Alan Turing"' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/name.json'
curl -X PUT -d '"June 23, 1912"' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/birthday.json'

上面的两个示例——将值作为对象同时写入并将它们分别写入子位置——将导致将相同的数据保存到我们的 Firebase 数据库中:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing"
    }
  }
}

成功的请求将由200 OK HTTP 状态码指示,响应将包含我们写入数据库的数据。第一个示例只会在正在查看数据的客户端上触发一个事件,而第二个示例将触发两个。需要注意的是,如果用户路径中已经存在数据,第一种方法会覆盖它,但第二种方法只会修改每个单独子节点的值,而其他子节点保持不变。 PUT相当于我们的 JavaScript SDK 中的set()

使用 PATCH 更新数据

使用PATCH请求,我们可以在不覆盖现有数据的情况下更新某个位置的特定子项。让我们通过PATCH请求将 Turing 的昵称添加到他的用户数据中:

curl -X PATCH -d '{
  "nickname": "Alan The Machine"
}' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'

上述请求会将nickname写入我们的alanisawesome对象,而不会删除namebirthday孩子。请注意,如果我们在此处发出PUT请求,则namebirthday将被删除,因为它们未包含在请求中。我们的 Firebase 数据库中的数据现在如下所示:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    }
  }
}

成功的请求将由200 OK HTTP 状态代码指示,响应将包含写入数据库的更新数据。

Firebase 还支持多路径更新。这意味着PATCH现在可以同时更新 Firebase 数据库中多个位置的值,这是一项强大的功能,可以帮助您对数据进行非规范化。使用多路径更新,我们可以同时为 Alan 和 Grace 添加昵称:

curl -X PATCH -d '{
  "alanisawesome/nickname": "Alan The Machine",
  "gracehopper/nickname": "Amazing Grace"
}' \
  'https://docs-examples.firebaseio.com/fireblog/users.json'

此次更新后,艾伦和格蕾丝都添加了昵称:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "date_of_birth": "December 9, 1906",
      "full_name": "Grace Hopper",
      "nickname": "Amazing Grace"
    }
  }
}

请注意,尝试通过写入包含路径的对象来更新对象将导致不同的行为。让我们看看如果我们尝试以这种方式更新 Grace 和 Alan 会发生什么:

curl -X PATCH -d '{
  "alanisawesome": {"nickname": "Alan The Machine"},
  "gracehopper": {"nickname": "Amazing Grace"}
}' \
  'https://docs-examples.firebaseio.com/fireblog/users.json'

这会导致不同的行为,即覆盖整个/fireblog/users节点:

{
  "users": {
    "alanisawesome": {
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "nickname": "Amazing Grace"
    }
  }
}

使用条件请求更新数据

您可以使用条件请求(相当于事务的 REST)根据其现有状态更新数据。例如,如果您想增加一个赞成票计数器,并希望确保计数准确反映多个同时赞成票,请使用条件请求将新值写入计数器。不是两次将计数器更改为相同数字的写入,而是其中一个写入请求失败,然后您可以使用新值重试请求。
  1. 要在某个位置执行条件请求,请获取该位置当前数据的唯一标识符或 ETag。如果该位置的数据发生变化,ETag 也会发生变化。您可以使用PATCH以外的任何方法请求 ETag。以下示例使用GET请求。
    curl -i 'https://test.example.com/posts/12345/upvotes.json' -H 'X-Firebase-ETag: true'
    
    专门调用header中的ETag,返回HTTP响应中指定位置的ETag。
    HTTP/1.1 200 OK
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    ETag: [ETAG_VALUE]
    Cache-Control: no-cache
    
    10 // Current value of the data at the specified location
    
  2. 在您的下一个PUTDELETE请求中包含返回的 ETag,以更新与该 ETag 值特别匹配的数据。按照我们的示例,要将计数器更新为 11,或者比初始获取的值 10 大 1,并且如果值不再匹配,则请求失败,请使用以下代码:
    curl -iX PUT -d '11' 'https://[PROJECT_ID].firebaseio.com/posts/12345/upvotes.json' -H 'if-match:[ETAG_VALUE]'
    
    如果指定的数据值location 还是 10, PUT请求中的 ETag 匹配,请求成功,将 11 写入数据库。
    HTTP/1.1 200 OK
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    Cache-Control: no-cache
    
    11 // New value of the data at the specified location, written by the conditional request
    
    如果位置不再与 ETag 匹配(如果另一个用户向数据库写入新值可能会发生这种情况),则请求会失败,但不会写入该位置。返回响应包括新值和 ETag。
    HTTP/1.1 412 Precondition Failed
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    ETag: [ETAG_VALUE]
    Cache-Control: no-cache
    
    12 // New value of the data at the specified location
    
  3. 如果您决定重试请求,请使用新信息。实时数据库不会自动重试失败的条件请求。但是,您可以使用新值和 ETag 使用失败响应返回的信息构建新的条件请求。

基于 REST 的条件请求实现 HTTP if-match标准。但是,它们在以下方面与标准不同:

  • 您只能为每个 if-match 请求提供一个 ETag 值,而不是多个。
  • 虽然标准建议所有请求都返回 ETag,但实时数据库只返回包含X-Firebase-ETag标头的请求的 ETag。这降低了标准请求的计费成本。

条件请求也可能比典型的 REST 请求慢。

保存数据列表

要为添加到 Firebase 数据库引用的每个子项生成唯一的、基于时间戳的密钥,我们可以发送POST请求。对于我们的users路径,定义我们自己的密钥是有意义的,因为每个用户都有一个唯一的用户名。但是当用户将博客文章添加到应用程序时,我们将使用POST请求为每个博客文章自动生成一个密钥:

curl -X POST -d '{
  "author": "alanisawesome",
  "title": "The Turing Machine"
}' 'https://docs-examples.firebaseio.com/fireblog/posts.json'

我们的posts路径现在包含以下数据:

{
  "posts": {
    "-JSOpn9ZC54A4P4RoqVa": {
      "author": "alanisawesome",
      "title": "The Turing Machine"
    }
  }
}

请注意,密钥-JSOpn9ZC54A4P4RoqVa是自动为我们生成的,因为我们使用了POST请求。成功的请求将由200 OK HTTP 状态代码指示,响应将包含添加的新数据的键:

{"name":"-JSOpn9ZC54A4P4RoqVa"}

删除数据

要从数据库中删除数据,我们可以发送一个DELETE请求,其中包含我们要从中删除数据的路径的 URL。以下将从我们的users路径中删除 Alan:

curl -X DELETE \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'

成功的DELETE请求将由200 OK HTTP 状态代码指示,响应包含 JSON null

URI 参数

将数据写入数据库时​​,REST API 接受以下 URI 参数:

授权

auth请求参数允许访问受Firebase 实时数据库规则保护的数据,并受所有请求类型的支持。参数可以是我们的 Firebase 应用程序机密或身份验证令牌,我们将在用户授权部分介绍。在以下示例中,我们发送带有auth参数的POST请求,其中CREDENTIAL是我们的 Firebase 应用程序机密或身份验证令牌:

curl -X POST -d '{"Authenticated POST request"}' \
  'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'

打印

print参数让我们指定来自数据库的响应的格式。在我们的请求中添加print=pretty将以人类可读的格式返回数据。 GETPUTPOSTPATCHDELETE请求支持print=pretty

为了在写入数据时抑制服务器的输出,我们可以将print=silent添加到我们的请求中。如果请求成功,则结果响应将为空,并由204 No Content HTTP 状态代码指示。 GETPUTPOSTPATCH请求支持print=silent

写入服务器值

服务器值可以使用占位符值写入某个位置,占位符值是具有单个".sv"键的对象。该键的值是我们希望设置的服务器值的类型。例如,要在创建用户时设置时间戳,我们可以执行以下操作:

curl -X PUT -d '{".sv": "timestamp"}' \
  'https://docs-examples.firebaseio.com/alanisawesome/createdAt.json'

"timestamp"是唯一支持的服务器值,它是自 UNIX 纪元以来的时间,以毫秒为单位。

提高写入性能

如果我们正在向数据库写入大量数据,我们可以使用print=silent参数来提高我们的写入性能并减少带宽使用。在正常的写入行为中,服务器以写入的 JSON 数据进行响应。当指定print=silent时,服务器在收到数据后立即关闭连接,减少带宽使用。

在我们向数据库发出许多请求的情况下,我们可以通过在 HTTP 标头中发送Keep-Alive请求来重用 HTTPS 连接。

错误条件

REST API 将在以下情况下返回错误代码:

HTTP 状态码
400错误请求

以下错误情况之一:

  • 无法解析PUTPOST数据。
  • 缺少PUTPOST数据。
  • 请求尝试PUTPOST太大的数据。
  • REST API 调用包含无效的子名称作为路径的一部分。
  • REST API 调用路径太长。
  • 请求包含无法识别的服务器值。
  • 您的Firebase 实时数据库规则中未定义查询的索引。
  • 该请求不支持指定的查询参数之一。
  • 该请求将查询参数与浅GET请求混合在一起。
401未经授权

以下错误情况之一:

  • 身份验证令牌已过期。
  • 请求中使用的身份验证令牌无效。
  • 使用 access_token 进行身份验证失败。
  • 该请求违反了您的Firebase 实时数据库规则。
404未找到未找到指定的 Firebase 数据库。
500内部服务器错误服务器返回错误。有关详细信息,请参阅错误消息。
503服务不可用指定的 Firebase 实时数据库暂时不可用,这意味着未尝试请求。

保护数据

Firebase 有一种安全语言,可以让我们定义哪些用户对我们数据的不同节点具有读写权限。您可以在实时数据库规则中了解更多信息。

现在我们已经介绍了保存数据,我们可以在下一节中学习如何通过 REST API 从 Firebase 数据库中检索数据。