Прослушиватели базы данных Firebase в реальном времени ведут себя по-разному в зависимости от правил безопасности

#firebase #firebase-realtime-database

#firebase #firebase-realtime-database

Вопрос:

В настоящее время я получаю неожиданное поведение от базы данных Firebase в реальном времени. Чтобы воспроизвести это, я использовал в точности приведенный ниже код, только используя Firebase JavaScript SDK ( 7.19.1 ) с ванильным JS.

Код:
Остается неизменным для обеих версий.
Только правила безопасности будут изменены непосредственно в Firebase.

 const CONFIG = { ... };  // TODO insert your config
const AUTH_TOKEN = "eyJ0..."  // TODO insert your auth token (JWT)

firebase.initializeApp(CONFIG);

firebase
  .auth()
  .signInWithCustomToken(AUTH_TOKEN)
  .then(() => {
    console.log("authentication successful");
    performFirebaseOperations();
  })
  .catch((error) => {
    console.log("authentication failed", error);
  });

const performFirebaseOperations = () => {
  const database = firebase.database();
  const allUsersRef = database.ref("users");
  const myUserRef = database.ref("users/1");

  allUsersRef.on("child_added", (data) => {
    console.log("child_added", data.val());
  });

  allUsersRef.on("child_removed", (data) => {
    console.log("child_removed", data.val());
  });

  myUserRef
    .update({
      name: "John",
    })
    .then(() => {
      console.log("update success");
    })
    .catch((error) => {
      console.log("update error", error);
    });
};

  

Версия 1

Правила безопасности:

 {
  "rules": {
    ".write": false,
    "users": {
      ".read": "auth !== null",
      "$userId": {
        ".write": false,
      }
    }
  }
}
  

Вывод на консоль:

введите описание изображения здесь


Версия 2

Правила безопасности:

 {
  "rules": {
    ".write": false,
    ".read": false
  }
}
  

Вывод на консоль:
введите описание изображения здесь


В обеих версиях в базу данных Firebase никогда ничего не записывается, поскольку правила безопасности этого не позволяют.

В этой статье объясняется, что операции с базой данных Firebase в реальном времени оптимистичны, что объясняет, почему child_added отображается в консоли, хотя оно никогда не записывалось в базу данных. Насколько я понимаю, версия 1 является ожидаемым поведением. Но почему версия 2 не показывает такое же поведение, хотя я только изменил правила безопасности? Я думал, что обновление является оптимистичным без предварительного обращения к серверу, поэтому я ожидал child_added события.

Ответ №1:

Я думаю, что я понял это, но это другой крайний случай.

Я смог получить тот же результат с правилами, которые разрешают запись, переведя клиент в автономный режим перед любой другой операцией.

 firebase.database().goOffline();
  

На этом этапе поведение с вашим первым набором правил такое же, как и со вторым набором правил.

Мой тестовый стенд, хотя вы не сможете изменить мои правила:https://jsbin.com/guzowak/edit?js ,консоль

Учитывая это…


Это сводится к гарантии того, что клиент Firebase никогда не покажет вам частичный снимок.

В вашем первом случае поток выглядит следующим образом:

  1. Ваш клиент прослушивает /users (для обоих child_added или child_removed , но для этого шага было бы достаточно любого из них), поэтому он получает снимок данных для всех пользователей.

  2. Затем вы выполняете запись в /users/1 , которая представляет собой модификацию узла, который клиент уже знает, чтобы он мог запустить локальное событие для этого изменения.

Во втором случае клиент никогда не получает данные для /users на шаге 1, поэтому он не может запустить событие на шаге 2.

Комментарии:

1. Это интересно. Я не получаю никаких выходных данных консоли, если раскомментирую goOffline часть. Я также пробовал это с моей версией, и моя консоль выводит только «аутентификация прошла успешно» и никаких других операций. Но я думаю, что это то, что вы имеете в виду? Что операция ничего не делает.

2. Если я изменю update операцию на set операцию с автономной версией, я получу тот же результат (только child_added событие). Думаю, теперь я это понимаю, потому что Firebase имеет локальную версию базы данных на стороне клиента, и в этой локальной версии путь для «пользователей» не существует, и поэтому он не может что-то здесь обновить, если я правильно понимаю.

3. Да, это последнее утверждение действительно является сутью. И извините, что не понял, что set() это исправит, поскольку это действительно решает проблему. От set() клиент может гарантировать, что теперь это полное значение узла. Для такого небольшого API база данных в реальном времени имеет много нишевого поведения. 🙂