如何在Cloud Function获取Firestore文档时启用文本压缩?
解决Cloud Function返回内容未压缩的Lighthouse警告
核心结论
Firebase Hosting确实会自动启用gzip/brotli压缩,但第二代Cloud Function默认不会自动对响应内容进行压缩,这就是你收到Lighthouse警告的原因。从你的响应头可以看到,返回内容没有Content-Encoding字段,而请求头已经明确告知客户端支持gzip, deflate, br压缩格式,导致传输了未压缩的384KiB数据。
解决方案:手动配置压缩
你可以通过两种方式实现响应压缩:
1. 使用Express中间件(推荐)
第二代Cloud Function支持Express风格的中间件,最简便的方式是使用compression包:
- 首先安装依赖:
npm install compression
- 修改你的Cloud Function代码:
const compression = require('compression'); const functions = require('firebase-functions'); const express = require('express'); const app = express(); // 启用压缩中间件 app.use(compression()); // 你的文档查询路由 app.get('/users/:userId/stories/:storyId', async (req, res) => { try { const storyPath = `users/${req.params.userId}/stories/${req.params.storyId}`; const doc = await db.doc(storyPath).get(); if (!doc.exists) { res.status(404).send('No such document!'); } else { // 返回JSON数据,中间件会自动压缩 res.status(200).json(doc.data()); } } catch (err) { console.error('Error getting document:', err); res.status(500).send('Error getting document'); } }); // 导出Cloud Function exports.api = functions.https.onRequest(app);
2. 手动压缩响应内容
如果不想用中间件,可以用Node.js内置的zlib模块手动压缩JSON数据:
const zlib = require('zlib'); // 在你的函数处理逻辑中 const docData = doc.data(); const jsonStr = JSON.stringify(docData); // 根据请求头选择压缩格式 const acceptEncoding = req.headers['accept-encoding'] || ''; if (acceptEncoding.includes('br')) { zlib.brotliCompress(jsonStr, (err, compressed) => { if (err) { res.status(500).send('Compression error'); return; } res.setHeader('Content-Encoding', 'br'); res.setHeader('Content-Type', 'application/json'); res.status(200).send(compressed); }); } else if (acceptEncoding.includes('gzip')) { zlib.gzip(jsonStr, (err, compressed) => { if (err) { res.status(500).send('Compression error'); return; } res.setHeader('Content-Encoding', 'gzip'); res.setHeader('Content-Type', 'application/json'); res.status(200).send(compressed); }); } else { // 不支持压缩,返回原始内容 res.status(200).json(docData); }
注意事项
- 仅对文本类内容(比如JSON、HTML)进行压缩,二进制内容无需处理
- 保留
Vary: Accept-Encoding响应头(你的现有响应头已包含,无需修改),这能让CDN正确缓存不同压缩格式的内容 - 使用
res.json()代替res.send()返回JSON数据,能自动设置正确的Content-Type为application/json,比当前的text/html更适配返回内容类型
内容的提问来源于stack exchange,提问作者redshift
相关产品推荐
相关产品推荐

