You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部署Firebase Functions后Google Drive文件回调的重复ID与两类网络错误求助

部署Firebase Functions后Google Drive文件回调的重复ID与两类网络错误求助

嘿,我来帮你排查这两个头疼的问题,咱们一个个来拆解分析:

一、重复收到文件ID的问题

看了你的代码,我发现几个核心原因:

  1. 全局变量urlArray的无状态干扰
    Firebase Functions是无状态的函数服务,实例可能会被复用,全局的urlArray不会在每次触发时自动重置。如果实例被重复调用,旧的fileId还留在数组里,新的变更处理时可能会出现判断逻辑失效,或者如果重复拉取同一批变更,就会重复输出ID。

  2. fetchChanges循环逻辑的错误
    你在fetchChanges里初始化pageToken = savedStartPageToken后,每次循环调用drive.changes.list时用的还是原始的savedStartPageToken,而不是更新后的pageToken!这会导致每次循环都拉取同一批变更,自然会重复输出fileId。

  3. Webhook中的实时监听触发循环
    在/webhooks/drive的POST处理里,你用了onValue实时监听数据库的/drive/token变化,而fetchChanges里又会更新这个token,这就形成了一个死循环:webhook触发→读取token→调用fetchChanges→更新token→onValue再次触发→重复处理同一批变更。

修复建议:

  • 把urlArray改成fetchChanges内的局部变量,每次调用时初始化,避免全局数据污染:
  • 修正循环逻辑,用当前的pageToken发起请求,而不是原始的savedStartPageToken:
  • 把Webhook里的onValue改成一次性读取的get,避免循环触发:

修改后的关键代码片段:

async function fetchChanges(authClient, savedStartPageToken) {
  const drive = google.drive({version: 'v3', auth: authClient});
  try {
    let pageToken = savedStartPageToken;
    // 局部数组,每次调用重置
    const urlArray = [];
    do {
      const res = await drive.changes.list({
        pageToken: pageToken, // 使用当前pageToken而非原始值
        includeRemoved: false,
        spaces: 'drive',
        fields: '*',
        pageSize: 50 // 限制单次拉取数量,避免超时
      });
      res.data.changes.forEach((change) => {
        if (change.file.parents && change.file.parents[0] === folderId && !change.file.trashed && !urlArray.includes(change.fileId)) {
          urlArray.push(change.fileId);
          console.log(change.fileId)
        }
      });
      pageToken = res.data.newStartPageToken;
      // 确保Firebase App只初始化一次
      if (!getApps().length) {
        initializeApp(firebaseConfig);
      }
      const database = getDatabase();
      await update(ref(database, "/drive"), {
        token: pageToken
      });
    } while (pageToken);
    return pageToken;
  } catch (err) {
    throw err;
  }
}

// Webhook POST处理修改
app.post('/webhooks/drive', async function (req, res) {
  res.status(200).send('OK');
  // 初始化Firebase App的统一判断
  if (!getApps().length) {
    initializeApp(firebaseConfig);
  }
  const database = getDatabase();
  const driveRef = ref(database, "/drive/token");
  // 一次性读取token,而非实时监听
  const snapshot = await get(driveRef);
  const driveToken = snapshot.val();
  await authorize()
    .then((authClient) => fetchChanges(authClient, driveToken))
    .catch(console.error);
});

二、部署后出现的网络错误

这两个错误(socket hang up和TLS连接断开)主要和Firebase Functions的执行特性、资源初始化有关:

  1. 重复初始化Firebase App
    你的代码在fetchChanges、watchChanges、Webhook处理里都调用了initializeApp(firebaseConfig),多次初始化App会引发内部资源冲突,干扰网络请求的正常建立。

  2. 函数执行时间过长
    如果fetchChanges的循环拉取大量变更,很容易超过Firebase Functions的执行时间限制(免费版默认90秒),函数被强制终止后就会出现socket hang up的错误。

  3. 网络请求超时未设置
    Google API的请求如果没有设置超时,遇到网络波动时可能会一直等待,最终触发连接断开的错误。

修复建议:

  • 所有需要使用Firebase的地方,统一添加App初始化判断,确保只初始化一次(上面的代码已经包含);
  • 给drive.changes.list添加pageSize参数,限制单次拉取的变更数量,避免函数超时;
  • 给Google Drive客户端设置超时时间,避免请求无限等待:
    const drive = google.drive({
      version: 'v3',
      auth: authClient,
      timeout: 30000 // 设置30秒超时
    });
    

备注:内容来源于stack exchange,提问作者leojail

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 14:19:36