假设我在firestore中有一个包含100,000条内容的数据库。每个内容不太可能每月更改一次。我的单页应用程序使用firebase托管,使用一个函数从firestore检索内容,将其呈现为HTML,然后将其返回给浏览器。
这是浪费我的火炬配额,并开始增加很多钱,如果我经常通过这个过程的内容不是动态。
如果请求确切的路径和查询,而不是通过firestore,那么如何将该内容保存为静态 .com / path / path / contentpage.html 文件/函数进程每次?
我的目标是提高速度,减少不必要的火葬场请求,知道每次阅读都要花钱。
谢谢!
答案 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操作。
这不仅便宜,而且比运行运行时服务器复杂,并且由于静态页面加载最快而提供最高的最终用户性能。