保存数据的方法 |
|
---|---|
PUT | 将数据写入到指定路径(例如 fireblog/users/user1/<data> )或替换指定路径下的数据 |
PATCH | 更新指定路径中的部分键,而不替换所有数据。 |
POST | 向 Firebase 数据库中的数据列表添加数据。每次发送 POST 请求时,Firebase 客户端会生成一个独一无二的键,例如 fireblog/users/<unique-id>/<data> |
删除 | 从指定 Firebase 数据库引用中移除数据。 |
使用 PUT 写入数据
通过 REST API 执行的基本写入操作为 PUT
。为了演示如何保存数据,我们将构建一个包含博文和用户的博客应用。此应用的所有数据都将存储在 `fireblog` 路径下,位于 Firebase 数据库网址 `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
对象中,而不会删除 name
或 birthday
子对象。请注意,如果我们将此处改为发出 PUT
请求,则 name
和 birthday
会被删除,因为该请求中不包括这些子节点。我们的 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'
执行此更新之后,Alan 和 Grace 均已添加各自的昵称:
{ "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 中相当于事务)根据数据的现有状态对其进行更新。例如,如果要增加点赞计数器的值,并且想确保该计数准确地反映同时进行的多次点赞,可使用条件请求向计数器写入新值。如果有两个同时发生的写入操作,系统不会根据这两个写入操作将计数器值更改为同一数值,而是会令其中一个写入请求失败,然后您可以使用新值重试该请求。- 如需在某个位置执行条件请求,请获取该位置的当前数据的唯一标识符(即 ETag)。如果该位置的数据发生更改,ETag 也会随之更改。您可以使用除
PATCH
之外的任何方法请求 ETag。下面的示例使用了GET
请求。curl -i 'https://test.example.com/posts/12345/upvotes.json' -H 'X-Firebase-ETag: true'
具体而言,在标头中调用 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
- 在您的下一个
PUT
或DELETE
请求中包含返回的 ETag,以更新与该 ETag 值匹配的数据。继续看我们的示例,如需将计数器值更新为 11(即比初始提取值 10 大 1),并在该值不再匹配时使请求失败,请使用以下代码:curl -iX PUT -d '11' 'https://[PROJECT_ID].firebaseio.com/posts/12345/upvotes.json' -H 'if-match:[ETAG_VALUE]'
如果指定位置的数据值仍为 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
- 如果您决定重试请求,请使用此新信息。Realtime Database 不会自动重试已失败的条件请求。但是,您可以使用新值和 ETag 根据失败响应返回的信息构建新的条件请求。
基于 REST 的条件请求实现了 HTTP if-match 标准。但是,它们与此标准在以下方面存在差异:
- 您只能为每个 if-match 请求提供一个(而不是多个)ETag 值。
- 此标准建议所有请求都返回 ETag,但 Realtime Database 仅为包含
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" } } }
请注意,由于我们使用了 POST
请求,因此系统自动为我们生成了 -JSOpn9ZC54A4P4RoqVa
键。成功的请求将返回 200 OK
HTTP 状态代码,并且响应中将包含添加的新数据的键:
{"name":"-JSOpn9ZC54A4P4RoqVa"}
移除数据
如需从数据库中移除数据,我们可以发送 DELETE
请求,其中包含我们想要从中删除数据的路径网址。下面的示例将从我们的 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
利用 auth
请求参数,您可以访问受 Firebase Realtime Database Security Rules 保护的数据。所有请求类型都支持该参数。该参数可以是我们的 Firebase 应用的 Secret 或是身份验证令牌,我们将在用户授权部分介绍这些内容。在下面的示例中,我们将发送带有 auth
参数的 POST
请求,其中 CREDENTIAL
是我们的 Firebase 应用的 Secret 或某个身份验证令牌:
curl -X POST -d '{"Authenticated POST request"}' \ 'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'
平面
我们可以使用 print
参数指定来自数据库的响应的格式。在我们的请求中添加 print=pretty
将以便于阅读的格式返回数据。GET
、PUT
、POST
、PATCH
和 DELETE
请求支持 print=pretty
。
在写入数据时,若要禁止服务器输出任何内容,我们可以在自己的请求中添加 print=silent
。由此产生的响应将是空的,如果请求成功,将返回 204 No Content
HTTP 状态代码。GET
、PUT
、POST
和 PATCH
请求支持 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 请求错误 |
以下错误情况之一:
|
401 未经授权 |
以下错误情况之一:
|
404 找不到 | 找不到指定的 Firebase 数据库。 |
500 内部服务器错误 | 服务器返回一个错误。如需了解详情,请参阅错误消息。 |
503 服务不可用 | 指定的 Firebase Realtime Database 暂不可用,意味着未尝试过发出请求。 |
保护数据
Firebase 采用了一种安全语言,我们可以通过这种语言定义哪些用户拥有对于我们数据中不同节点的读写访问权限。如需了解详情,请参阅 Realtime Database Security Rules。
上面我们介绍了如何保存数据,在下一部分中,我们将学习如何通过 REST API 从 Firebase 数据库中检索数据。