【问题标题】:"Failed to get document because the client is offline" Firebase error with the firestore emulator“由于客户端离线,无法获取文档”Firestore 模拟器的 Firebase 错误
【发布时间】:2022-01-17 13:46:27
【问题描述】:

编辑:我知道它与模拟器有关,因为没有它们它可以正常工作。

我正在关注course for Next js,我正在使用 Firebase 模拟器(它建议这样做,但没有教程可以这样做,因为它非常简单),我正在尝试从 firestore 读取一些数据用户,但它总是得到错误,Failed to get document because the client is offline。 auth 模拟器工作正常,但 firestore 没有。即使我与互联网断开连接(我不是因为我正在写这个问题并且可以访问任何网站)我知道为什么它会出现该错误,因为该网站托管在下一个 js 上。这是我在课程中制作的用于连接到 Firebase 的自定义钩子:

import { initializeApp } from "firebase/app";
import {
    getAuth,
    signInWithPopup,
    signOut,
    signInAnonymously,
    GoogleAuthProvider,
    connectAuthEmulator,
} from "firebase/auth";
import { getFirestore, doc, onSnapshot, connectFirestoreEmulator, getDoc } from "firebase/firestore";

const firebaseConfig = {
    apiKey: "MY APIKEY",
    authDomain: "My AUTH DOMAIN",
    projectId: "nextfirE (in the course i am using we are making are making a blog type app called nextfire)",
    storageBucket: "STOREAGEBUKET DOMAIN",
    messagingSenderId: "messagingSenderId",
    appId: "aPP id",
    measurementId: "measurementId",
};

const firebase = initializeApp(firebaseConfig);
const auth = getAuth();
const db = getFirestore()
export {
    GoogleAuthProvider,
    auth,
    signInWithPopup,
    signOut,
    signInAnonymously,
    db,
    doc,
    onSnapshot,
    getDoc
};

if (window.location.hostname === "localhost") {
    connectAuthEmulator(auth, "http://localhost:9099");
    connectFirestoreEmulator(db, "https://localhost", 8080)
}

这是一个用户名表单,这里是处理表单的反应组件:

function Username() {
    const [formValue, setFormValue] = useState("");
    const [isValid, setIsValid] = useState(false);
    const [loading, setLoading] = useState(false);

    const { user, username } = useContext(UserContext);

    useEffect(() => {
        checkUsername(formValue);
    }, [formValue]);

    const onChange = (e) => {
        const val = e.target.value.toLowerCase();
        const regex = /^(?=[a-zA-Z0-9._]{3,15}$)(?!.*[_.]{2})[^_.].*[^_.]$/;

        if (val.length < 3) {
            setFormValue(val);
            setLoading(false);
            setIsValid(false);
        }

        if (regex.test(val)) {
            setFormValue(val);
            setLoading(true);
            setIsValid(false);
        }
    };

    const checkUsername = useCallback(
        debounce(async (username: string) => {
            if (username.length >= 3) {
                const ref = doc(db, `usernames/${username}`);
                const docSnap = await getDoc(ref);

                if (docSnap.exists()) {
                    setIsValid(true);
                    setLoading(false);
                } else {
                    setIsValid(false);
                    setLoading(false);
                }
            }
        }, 500),
        []
    );

    return (
        !username && (
            <section>
                <h3>Choose Your Username</h3>
                <form>
                    <input
                        name="username"
                        placeholder="username"
                        value={formValue}
                        onChange={onChange}
                    />
                    <button
                        type="submit"
                        className="btn-green"
                        disabled={!isValid}
                    >
                        Take Username
                    </button>

                    <h3>Debug State</h3>
                    <div>
                        Username: {formValue}
                        <br />
                        Loading: {loading.toString()}
                        <br />
                        Username Valid: {isValid.toString()}
                    </div>
                </form>
            </section>
        )
    );
}

它有一些正则表达式检查和长度检查,但是如果它通过了这些检查,则会进入 firestore,当我输入一个已经被使用的用户名时(如果它已经被使用,将会有一个以用户名作为名称存在的 firestore 文档的文档)显示错误需要几秒钟,但是当我输入一个尚未被使用的有效用户名时,它会立即给我一个错误。你能帮帮我吗?

谢谢

【问题讨论】:

  • 另外,将您的代码修复为“connectFirestoreEmulator(db, "localhost", 8080)"
  • @Alien10 我已经发布了一个答案,以供将来遇到此问题的任何人参考。我已经涵盖了可能导致此错误的所有可能原因/原因。我什至指出您的解决方案是解决方案之一。请仔细阅读答案,如果您认为我的答案有用,请点击它左侧的点赞按钮 (▲)。

标签: reactjs firebase google-cloud-firestore next.js


【解决方案1】:

感谢 Gourav B,我能够找到答案。我只需要在 connectFirestoreEmulator 中删除 localhost 前面的 https://。我猜他们在 connectFirestoreEmulator 中连接到 https:// + 主机 + 端口(主机和端口是第二个和第三个参数)。谢谢 Gourav B!

【讨论】:

    【解决方案2】:

    客户端离线,获取文档失败

    当您尝试检索单个文档、您处于脱机状态并且本地缓存中不存在所请求的文档时会发生错误。在这种情况下,客户端没有关于文档的信息,也不知道它是否存在于后端。在重新建立网络连接之前,无法知道文档是否存在。所以为了避免错误地报告一个文档不存在,就会产生这个错误。

    通过在在线状态下获取文档以使其存在于本地缓存中,可以在很大程度上避免这种情况。但是请注意,本地缓存是一个缓存,“陈旧”条目可能会从缓存中清除,以便为其他数据腾出空间。如果文档中的数据不经常更改,您也可以通过addSnapshotListener() 注册一个快照侦听器并保持侦听器处于活动状态以确保文档保留在本地缓存中。 此外,此错误可能还有多种其他原因,其中一些是:

    1. 您试图引用尚未创建的集合/文档。因此,只需使用虚拟文档创建一个集合,或者等待文档创建并查看它是否正常工作。
    2. 实现 try ... 捕获所有 get().await() 调用。未处理的异常可能导致此错误
    3. 问题已通过更改模拟器的端口号得到解决。如果 8080 不起作用,请尝试 8081,

    也根据Firebase documentationGitHub link 更改,

    if (window.location.hostname === "localhost") {
     connectAuthEmulator(auth, "http://localhost:9099");
     connectFirestoreEmulator(db, "https://localhost", 8080) }
    

    if (window.location.hostname === "localhost") { 
    connectAuthEmulator(auth, "http://localhost:9099"); 
    connectFirestoreEmulator(db, "localhost", 8080) }
    
    1. 更新所有包并为您的网络应用启用离线持久性,如下所示:

      firebase.firestore().enablePersistence()

    https://firebase.google.com/docs/firestore/manage-data/enable-offline

    [5] 这也可能是因为OnCompleteListener 在任务完成时触发,要么失败,要么成功。为避免该错误,您可以使用单独的OnSuccessListenerOnFailureListener 任务成功时调用OnSuccessListener,但如果出现上述错误,则会触发OnFailureListener,您可以在监听器的onFailure()方法中处理错误。

    [6] 将项目 ID 传递给 initializeApp 或设置环境变量时检查项目 ID 是否正确。

    admin.initializeApp({ projectId: "your-project-id" });
    

    或者

    export GCLOUD_PROJECT="your-project-id"
    

    如果仍然遇到问题,请尝试按照此documentation 将您的应用连接到 Firestore 模拟器,我还推荐enabling debug logging 以查看它是否会提示客户端无法连接的原因。

    【讨论】:

      猜你喜欢
      • 2022-07-01
      • 2020-07-12
      • 2018-03-18
      • 1970-01-01
      • 2019-05-18
      • 2021-11-08
      • 2018-09-24
      • 2021-01-02
      • 2018-03-19
      相关资源
      最近更新 更多