如何为Cloud Functions的onCall请求添加调用延迟防滥用?
实现Cloud Functions onCall请求的用户级限流(10秒冷却)
要实现同一用户10秒内只能发起一次onCall请求,其余请求直接返回提示,可以通过Firestore存储用户最后请求时间的方式实现,具体方案如下:
核心逻辑
- 利用用户UID(从
context.auth获取)作为唯一标识,跟踪请求时间 - 每次请求先检查该用户最后一次请求的时间戳,若距离当前时间不足10秒,直接返回错误提示
- 若通过检查,更新用户的最后请求时间,再执行写入Firestore的业务逻辑
完整代码示例
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); const COOLDOWN_SECONDS = 10; // 冷却时间:10秒 const TIMESTAMP_COLLECTION = "userRequestTimestamps"; // 存储请求时间的集合 exports.sendToFirestore = functions.https.onCall(async (data, context) => { // 1. 验证用户身份:未登录用户直接拒绝 if (!context.auth) { throw new functions.https.HttpsError( "unauthenticated", "用户未登录,无法发起请求" ); } const userId = context.auth.uid; const now = Date.now(); const timestampRef = admin.firestore().collection(TIMESTAMP_COLLECTION).doc(userId); try { // 2. 获取用户最后请求时间 const doc = await timestampRef.get(); const lastRequestTime = doc.exists ? doc.data().lastRequest : 0; // 3. 检查是否在冷却期内 if (now - lastRequestTime < COOLDOWN_SECONDS * 1000) { throw new functions.https.HttpsError( "failed-precondition", "请10秒后重试" ); } // 4. 更新用户最后请求时间 await timestampRef.set({ lastRequest: now }, { merge: true }); // 5. 执行写入Firestore的业务逻辑 const targetCollection = admin.firestore().collection("yourTargetCollection"); // 替换为你的目标集合 await targetCollection.add(data); // 写入请求数据 return { success: true, message: "数据已成功提交" }; } catch (error) { // 统一处理错误 if (error instanceof functions.https.HttpsError) { throw error; } throw new functions.https.HttpsError( "internal", "服务器内部错误,请稍后重试" ); } });
注意事项
- Firestore权限配置:需要确保Cloud Functions服务账号拥有
userRequestTimestamps集合的读写权限,避免出现权限错误 - 异步处理:所有Firestore操作都是异步的,必须使用
async/await或者Promise链式调用,否则会出现逻辑错误 - 错误类型:使用Firebase官方的
HttpsError类型返回错误,前端可以根据错误代码做对应的提示处理
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

