Firebase Firestore 模拟器错误`主机已在 settings() 和 useEmulator() 中设置,将使用模拟器主机`

Posted

技术标签:

【中文标题】Firebase Firestore 模拟器错误`主机已在 settings() 和 useEmulator() 中设置,将使用模拟器主机`【英文标题】:Firebase Firestore emulator error `Host has been set in both settings() and useEmulator(), emulator host will be used` 【发布时间】:2021-03-11 23:38:39 【问题描述】:

首先,这是我得到的完整错误。

@firebase/firestore:Firestore (8.1.1):主机已在 settings() 和 useEmulator() 中设置,将使用模拟器主机 错误 [FirebaseError]:Firestore 已启动,无法再更改其设置。您只能在调用 Firestore 对象上的任何其他方法之前修改设置。

这就是我启动模拟器的方式

const db = app.firestore();
const auth = firebase.auth();
if (process.env.NODE_ENV === 'development') 
  db.useEmulator('localhost', 8888);
  firebase.auth().useEmulator('http://localhost:9099/');

当我第一次启动应用程序时,项目正在运行 nextjs,一切都按预期运行,但是在 next.js 页面之间进行一些刷新或导航后,我突然收到此错误。我必须杀死终端并重新开始,这很烦人我不知道 next.js 服务器是否多次运行 if (process.env.NODE_ENV === 'development') 代码,如果是这种情况,这可能是导致此错误的原因如何避免设置新的模拟器,当已经有一个时。还是与 firebase 模拟器相关的错误?

【问题讨论】:

您是否从数据库设置中启用 Persistence 参数?我找到了this GitHub issue,其中提到了 Persistence,但出现了类似的错误。 @ArtemisGeorgakopoulou 不,我实际上没有添加任何自定义设置,我只使用 useEmulator 方法,但在此之前,我将开发中的本地主机添加为 js firestore().settings( host: 'http://localhost:8080', ssl: false ) 但我有这个错误``` 错误 [FirebaseError]:Firestore 已启动,无法再更改其设置。您只能在调用 Firestore 对象上的任何其他方法之前修改设置。 ``` 当我使用 useEmulator 时,它经常发生,但很少发生。 1500 以上的人可以建议在 *** 上使用 Firebase-emulators 标签吗? 在“db.useEmulator('localhost', 8888);”行中,你有没有尝试过设置8080端口而不是设置中的配置? Postgres 使用 8080,所以我将 8888 配置为 firestore 的端口 【参考方案1】:

NextJs 正在热重新加载网页,xxx.useEmulator(...) 正在为同一个 browser 实例调用两次。

Firebase 库在后台使用对当前应用的全局引用,从库的角度来看,您尝试对其进行两次或更多次初始化。

您可以使用以下代码重现此问题:

const db = app.firestore();
db.useEmulator('localhost', 8888);
db.useEmulator('localhost', 8888); // raises error

我发现的唯一解决方法是使用 window 对象来保存一个标志(如果它已被初始化),但您还必须处理 s-s-r 的边缘情况。

const db = app.firestore();
if(typeof window === 'undefined' || !window['_init']) 
   db.useEmulator('localhost', 8888);
   if(typeof window !== 'undefined') 
      window['_init'] = true;
   

这不是上面最优雅的代码,但它修复了错误。

关键是要知道热重载是问题所在,Firebase应该只配置一次。

【讨论】:

我想将它标记为解决方案,但我想我会给它一天或更长时间以确保它是解决方案,因为我面临的错误并不总是发生。谢谢【参考方案2】:

我同意@Reactgular 关于原因的评估。但在我的情况下,全局解决方案不太适合,因为错误是在测试期间抛出的,它们应该被隔离。

我还必须处理“清除仿真器数据”逻辑,与 useEmulator 相对应在每次初始化时调用。

为了解决这个问题,我发现 Firestore 对象内部的“主机”属性在我们调用 useEmulator 后发生了变化。然后我开始在命令 useEmulator 之前检查该属性。

代码如下:

import  del  from '../request';

async function initFirestore (config) 
  const  suite, firestoreEmulatorHost  = config;
  const  app, projectId  = suite;

  const firestore = app.firestore();

  if (firestoreEmulatorHost) 
    plugEmulator(firestore, firestoreEmulatorHost);
    await clearFirestoreEmulator(projectId, firestoreEmulatorHost);
  

  return firestore;


export function plugEmulator (firestore, firestoreEmulatorHost) 
  const settingsHost = firestore._delegate._settings.host;
  const isUnplugged = !settingsHost.includes(firestoreEmulatorHost);

  if (isUnplugged) 
    firestore.useEmulator('localhost', firestoreEmulatorHost);
  


export function clearFirestoreEmulator (projectId, firestoreEmulatorHost) 
  const clearUrl = `http://localhost:$firestoreEmulatorHost/emulator/v1/projects/$projectId/databases/(default)/documents`;
  return del(clearUrl);

【讨论】:

【参考方案3】:

在这里尝试了几乎所有的解决方案后,它并没有真正起作用,这个错误时常发生,令人讨厌的是我不知道如何重现它,但我认为当这个页面有服务器时它会发生无论如何,我用来解决此错误的解决方案如下

const EMULATORS_STARTED = 'EMULATORS_STARTED';
function startEmulators() 
  if (!global[EMULATORS_STARTED]) 
    global[EMULATORS_STARTED] = true;
    firebase.firestore().useEmulator('localhost', 8888);
    firebase.auth().useEmulator('http://localhost:9099/');
  


if (process.env.NODE_ENV === 'development') 
  startEmulators();

但要使其按预期工作,您需要确保所有模拟器都已启动,然后再向 next.js 服务器发出请求,因为如果此代码在模拟器启动之前执行,则 global[EMULATORS_STARTED] 将为 true 并且在这种情况下,它永远不会使用模拟器。 我已经在很多页面上对此进行了测试,其中一些页面出现了服务器端错误,并且错误没有发生,而是我得到了这些错误的日志,这是预期的行为,我不知道这些错误在申请之前首先存在这个解决方案?。

【讨论】:

我遇到了一个打字稿错误,由于某种原因阻止了它的工作,但将文件更改为 .js 并且现在可以工作了。谢谢。

以上是关于Firebase Firestore 模拟器错误`主机已在 settings() 和 useEmulator() 中设置,将使用模拟器主机`的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 React Native 中的 Firebase/firestore 错误?

Firebase Firestore:无法访问Firestore后端(仅限Android)

Firestore/Firebase 模拟器未运行

Firebase 模拟器对本地 FireStore 的请求不成功

React Native Firebase Cloud Firestore

在 Jest 中模拟 Firebase 管理员时出错:“TypeError:admin.firestore 不是函数”