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

使用Google Apps Script调用Clockify API分页取数时的无限循环问题

Clockify API分页拉取数据无限循环问题排查与解决

问题背景

开发Google Apps Script从Clockify API拉取2023全年数据到Google Sheet,API单请求最多返回50条数据,实现分页逻辑后陷入无限循环,始终获取前50条数据,即便递增了page参数。

核心问题原因

你的代码中将分页参数page和pageSize放在了请求参数的顶层,但根据Clockify Detailed Reports API的规范,分页参数属于detailedFilter对象的子属性。参数位置错误导致API无法识别分页指令,始终返回第一页数据,进而触发无限循环。

修复方案

将page和pageSize移至detailedFilter对象内部,修改后的关键参数部分代码如下:

var params = {
  "dateRangeStart": startDate,
  "dateRangeEnd": endDate,
  "dateRangeType": "ABSOLUTE",
  "detailedFilter": {
    "sortOrder": "DESCENDING",
    "sortColumn": "DATE",
    "page": page, // 移到detailedFilter内部
    "pageSize": pageSize // 移到detailedFilter内部
  },
  "users": {
    "status": "ACTIVE"
  }
};

完整修复后的脚本:

function pullDataFromClockify() {
  var apiKey = "XXXX";
  var workspaceId = "XXXX";
  var apiUrl = "https://reports.api.clockify.me/v1/workspaces/" + workspaceId + "/reports/detailed";

  var startDate = "2023-01-01T00:00:00Z";
  var endDate = "2023-12-31T23:59:59Z";
  
  var headers = {
    "X-Api-Key": apiKey,
    "Content-Type": "application/json"
  };

  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName("Clocky_Exp"); 

  if (!sheet) {
    sheet = spreadsheet.insertSheet("Clocky_Exp");
  }

  var page = 1; 
  var pageSize = 50; 
  var allEntries = []; // 收集所有条目,批量写入提升性能

  while (true) {
    var params = {
      "dateRangeStart": startDate,
      "dateRangeEnd": endDate,
      "dateRangeType": "ABSOLUTE",
      "detailedFilter": {
        "sortOrder": "DESCENDING",
        "sortColumn": "DATE",
        "page": page,
        "pageSize": pageSize
      },
      "users": {
        "status": "ACTIVE"
      }
    };

    Logger.log("Fetching page: " + page); 
    Logger.log(JSON.stringify(params));  

    var options = {
      "method" : "POST",
      "headers" : headers,
      "muteHttpExceptions": true,
      "payload": JSON.stringify(params)
    };

    var response = UrlFetchApp.fetch(apiUrl + "?_t=" + new Date().getTime(), options);
    var jsonResponse = JSON.parse(response.getContentText());

    // 检查HTTP状态码,处理错误
    if (response.getResponseCode() !== 200) {
      Logger.log("API请求错误,状态码: " + response.getResponseCode());
      Logger.log("错误响应: " + response.getContentText());
      break;
    }

    if (!jsonResponse.timeentries || jsonResponse.timeentries.length === 0) {
      Logger.log("无更多数据,退出循环");
      break;  
    }

    var entries = jsonResponse.timeentries;
    // 处理当前页数据,存入allEntries
    for (var i = 0; i < entries.length; i++) {
      var start = new Date(entries[i].timeInterval.start);
      var end = new Date(entries[i].timeInterval.end);
      var duration = (end - start) / (1000 * 60 * 60); 
      var formattedStartDate = Utilities.formatDate(start, "GMT", "yyyy.MM.dd");

      allEntries.push([
        entries[i].description,
        entries[i].taskName,
        entries[i].userEmail,
        formattedStartDate,
        duration
      ]);
    }

    // 用API返回的totalPages判断是否最后一页(更可靠)
    if (jsonResponse.totalPages && page >= jsonResponse.totalPages) {
      Logger.log("已获取最后一页,退出循环");
      break;
    }

    // 备用判断:如果返回条目数小于页大小,视为最后一页
    if (entries.length < pageSize) {
      Logger.log("返回条目数不足页大小,视为最后一页");
      break;
    }

    page++;  
    Logger.log("准备获取下一页: " + page);

    Utilities.sleep(5000);  
  }

  // 批量写入数据到Sheet,大幅提升性能
  if (allEntries.length > 0) {
    var nextRow = sheet.getLastRow() + 1;
    sheet.getRange(nextRow, 1, allEntries.length, allEntries[0].length).setValues(allEntries);
  }
}

调试与优化建议

  • 验证参数结构:打印请求的payload确认page和pageSize在detailedFilter内,可直接查看Logger.log(JSON.stringify(params))的输出
  • 利用API分页元数据:Clockify API响应会返回totalPages和totalEntries字段,用page >= totalPages判断循环终止,比仅靠条目数更可靠
  • 优化Sheet写入:避免循环调用appendRow,改用批量setValues,减少脚本执行时间和Google服务调用次数
  • 增强错误处理:检查API响应状态码,对429(速率限制)可实现指数退避重试,对其他错误及时终止并记录日志
  • 日志细化:记录响应中的totalPages、page等信息,方便跟踪分页进度

内容的提问来源于stack exchange,提问作者Levi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 10:44:51