Firebase托管可以从云功能提供缓存数据吗?

时间:2017-12-14 20:42:11

标签: firebase caching google-cloud-functions google-cloud-firestore firebase-hosting

假设我在firestore中有一个包含100,000条内容的数据库。每个内容不太可能每月更改一次。我的单页应用程序使用firebase托管,使用一个函数从firestore检索内容,将其呈现为HTML,然后将其返回给浏览器。

这是浪费我的火炬配额,并开始增加很多钱,如果我经常通过这个过程的内容不是动态

如果请求确切的路径和查询,而不是通过firestore,那么如何将该内容保存为静态 .com / path / path / contentpage.html 文件/函数进程每次?

我的目标是提高速度,减少不必要的火葬场请求,知道每次阅读都要花钱。

谢谢!

4 个答案:

答案 0 :(得分:4)

Firebase Hosting之上使用Cloud Functions for Firebase时,托管可以作为HTTPS功能响应之上的边缘缓存层。您可以在documentation中了解该集成。请特别阅读managing cache behavior部分:

  

您用来管理缓存的主要工具是Cache-Control标头。   通过设置,您可以与浏览器和CDN进行通信   应该缓存您的内容。在你的功能中,你设置   像这样的缓存控制:

res.set('Cache-Control', 'public, max-age=300, s-maxage=600');

答案 1 :(得分:2)

除了设置Cache-Control标头之外,您还可以利用Cloud Functions实例中全局变量设置的好处,参见Cloud Functions Tips他们提到的地方“使用全局变量在将来的调用中重用对象”。

有了这个想法,我就可以使用npm package treasury了(是的,我确实开发了这个,但这与它恰好与Cloud Functions中的这个用例一起使用这一事实无关 - 我也在生产中使用它如果它让你感觉更好)。

只要存在变量treasury,它就会利用Treasury的“Memory”适配器来存储数据的示例,它与Cloud Function实例一起生存和死亡:

const functions = require('firebase-functions');
const tauist = require('tauist');
const Treasury = require('treasury');
const cors = require('cors')({
    origin: true
});

// note that memory adapter uses MS not S for ttl
const treasury = new Treasury({
    ttl: tauist.ms.thirtyMinutes
});

function getAnimalData({name}) {
    // replace this with your actual Promise code doing the "real work" that you want to cache
    return new Promise();
}

exports.animal = functions.https.onRequest((req, res) => {
    if (req.method !== 'GET') {
        return res.status(403).send('Forbidden');
    }

    // Enable CORS using the `cors` express middleware.
    return cors(req, res, () => {
        // Reading ticker symbol from URL query parameter.
        let name = (req.query.name || '').trim();
        console.log('animal name:', name);

        if (!name) {
            return res.status(400).send('Bad Request');
        }

        res.set('Cache-Control', `public, max-age=${tauist.s.thirtyMinutes}, s-maxage=${tauist.s.thirtyMinutes}`);
        treasury.invest(getAnimalData, {name})
            .then((data) => res.status(200).send(data))
            .catch((error) => {
                console.error('error caught:', error);
                res.status(500).send('Internal Server Error');
            });

    });
});

答案 2 :(得分:0)

如果您需要缓存一些非常昂贵的结果,或者可能来自其他API,则可以将fireStore用作“提供者”。我的操作从约30秒延长到了约1秒。您将减少出站配额的使用量

以下是示例代码,我在服务中创建了一个方法:

             ...
    import {db} from "../database";
    const tauist = require('tauist');

    ... 

    /**
     * @param name must be uniq
     * @param fallback
     * @param parameters
     * @param namespace
     * @param ttl milliseconds
     */
    static async getCache(name: string, fallback: (...a: any) => Promise<any>, parameters: any[], ttl: number = tauist.s.thirtyDays, namespace: string = 'api') {
        let response = {};
        const parms = parameters || [];
        const now = new Date();
        const collectionRef = db.collection(`cache-${namespace}-${parms.join('-')}`);
        const documentRef = collectionRef.doc(name);
        try {
            const cacheSnapshot = await documentRef.get();
            if (cacheSnapshot.exists) {
                const cache = cacheSnapshot.data();
                if (new Date(new Date((cache as Cache).created).getTime() + ttl) < now) {
                    throw new Error();
                } else {
                    response = (cache as Cache).data;
                }
                // Using cache
            } else {
                throw new Error();
            }
        } catch (e) {
            // Cache created
            response = await fallback(...parms);
            await documentRef.set({
                data: response,
                created: new Date(new Date().getTime() + ttl)
            })
        }

        return response;
    }

我如何使用它:

import {INTERNAL_SERVER_ERROR, OK, UNPROCESSABLE_ENTITY} from "http-status-codes";
...
Service.getCache('getHugeData',  AWSService.getHugeData, [name, simple])
                .then((data: any) => {
                    res.status(OK).json({
                        data
                    });
                })
                .catch((error: any) => {
                    console.log(error);
                    res.status(UNPROCESSABLE_ENTITY).json(error);
                });

答案 3 :(得分:0)

这是JAMstack样式体系结构的一个好用例,您可以在其中预呈现页面,并在构建时加载所需的数据。您可以将预渲染的静态站点构建器视为另一种缓存形式。在这种情况下,考虑到您希望每月进行一次更新,根本就不需要在运行时对服务器进行页面渲染。

数据更改后,只需重建您的站点即可。为此设置了Gastby(在react世界中),它具有许多可插入构建器的数据源,包括用于firestore的插件。

Netlify是具有webook触发重建的静态站点主机。您可以使用由事件触发的Firebase云功能来对各种Firestore集合/文档进行事件,这些ping / Netlify会在插入/更新/删除时对Netlify进行ping操作。

这不仅便宜,而且比运行运行时服务器复杂,并且由于静态页面加载最快而提供最高的最终用户性能。