保存數據

保存數據的方法

將數據寫入或替換到定義的路徑,例如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請求將圖靈的暱稱添加到他的用戶數據中:

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'

本次更新後,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)根據數據的現有狀態更新數據。例如,如果您想增加一個投票計數器,並希望確保計數準確反映多個同時進行的投票,請使用條件請求將新值寫入計數器。不是將計數器更改為相同數字的兩次寫入,而是其中一次寫入請求失敗,然後您可以使用新值重試該請求。
  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將以人類可讀的格式返回數據。 print=prettyGETPUTPOSTPATCHDELETE請求支持。

要在寫入數據時抑制服務器的輸出,我們可以在我們的請求中添加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 Realtime Database Rules中定義。
  • 該請求不支持指定的查詢參數之一。
  • 該請求將查詢參數與淺層GET請求混合在一起。
401未經授權

以下錯誤情況之一:

  • 授權令牌已過期。
  • 請求中使用的身份驗證令牌無效。
  • 使用 access_token 進行身份驗證失敗。
  • 該請求違反了您的Firebase 實時數據庫規則。
404未找到找不到指定的 Firebase 數據庫。
500內部服務器錯誤服務器返回錯誤。有關詳細信息,請參閱錯誤消息。
503服務不可用指定的 Firebase 實時數據庫暫時不可用,這意味著未嘗試請求。

保護數據

Firebase 有一種安全語言,可以讓我們定義哪些用戶對我們數據的不同節點具有讀寫權限。您可以在實時數據庫規則中閱讀更多相關信息。

現在我們已經介紹了保存數據,我們可以在下一節中學習如何通過 REST API 從 Firebase 數據庫中檢索數據。