为何同一脚本可获取本人Nest温控器ID,他人使用却报错?
TypeError: Cannot read properties of undefined (reading 'forEach') 错误分析与修复
问题背景
我编写了一个包含listDevices函数的脚本用于获取Nest温控器ID,该脚本在我的Nest设备上运行正常,但当另一拥有多台Nest温控器的用户使用时,出现错误:TypeError: Cannot read properties of undefined (reading 'forEach')。以下是相关代码:
相关代码
listDevices函数
function listDevices() { // specify the endpoint const endpoint = '/enterprises/' + PROJECT_ID + '/devices'; // blank array to hold device data let deviceArray = []; // make request to smart api const data = makeRequest(endpoint); const deviceData = data.devices; console.log(deviceData); deviceData.forEach(device => { const name = device.name; const type = device.type; deviceArray.push([name,type]); }); // get the Sheet const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getActiveSheet(); // output the data sheet.getRange(2,1,deviceArray.length,2).setValues(deviceArray); }
makeRequest函数
function makeRequest(endpoint) { // get the smart service const smartService = getSmartService(); // get the access token const access_token = smartService.getAccessToken(); //console.log(access_token); // setup the SMD API url const url = 'https://smartdevicemanagement.googleapis.com/v1'; //const endpoint = '/enterprises/' + PROJECT_ID + '/devices'; // setup the headers for the call const headers = { 'Authorization': 'Bearer ' + access_token, 'Content-Type': 'application/json' } // set up params const params = { 'headers': headers, 'method': 'get', 'muteHttpExceptions': true } // try calling API try { const response = UrlFetchApp.fetch(url + endpoint, params); const responseBody = JSON.parse(response.getContentText()); return responseBody; } catch(e) { console.log('Error: ' + e); } }
错误原因分析
报错直接指向deviceData.forEach这一行,说明deviceData为undefined,即data.devices不存在。核心原因如下:
- API错误响应未处理:
makeRequest中设置了muteHttpExceptions: true,即使API返回401(权限无效)、403(无访问权限)等错误状态码,也不会抛出异常,而是返回包含错误信息的响应体(无devices字段),此时data.devices自然为undefined。 - 异常场景无返回值:
makeRequest的catch块仅打印错误但未返回任何值,若出现JSON解析失败等异常,函数会返回undefined,后续访问data.devices也会触发错误。 - 权限或配置问题:多设备用户可能未正确授权项目访问其所有设备,或使用了错误的
PROJECT_ID,导致API返回无设备数据的响应。
修复方案
1. 增加数据合法性校验
在listDevices中先校验数据有效性,避免直接调用forEach:
function listDevices() { const endpoint = '/enterprises/' + PROJECT_ID + '/devices'; let deviceArray = []; const data = makeRequest(endpoint); // 可选链+数组类型校验,避免undefined报错 const deviceData = data?.devices; if (Array.isArray(deviceData)) { deviceData.forEach(device => { const name = device.name; const type = device.type; deviceArray.push([name, type]); }); } else { console.log("获取设备数据失败,响应内容:", data); // 给用户直观提示 const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getActiveSheet(); sheet.getRange(2,1).setValue("获取设备数据失败,请检查权限或项目配置"); return; } const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getActiveSheet(); sheet.getRange(2,1,deviceArray.length,2).setValues(deviceArray); }
2. 完善API错误处理
在makeRequest中检查响应状态码,明确区分成功与失败场景:
function makeRequest(endpoint) { const smartService = getSmartService(); const access_token = smartService.getAccessToken(); const url = 'https://smartdevicemanagement.googleapis.com/v1'; const headers = { 'Authorization': 'Bearer ' + access_token, 'Content-Type': 'application/json' }; const params = { 'headers': headers, 'method': 'get', 'muteHttpExceptions': true }; try { const response = UrlFetchApp.fetch(url + endpoint, params); const statusCode = response.getResponseCode(); // 仅处理200系列成功响应 if (statusCode >= 200 && statusCode < 300) { const responseBody = JSON.parse(response.getContentText()); return responseBody; } else { const errorBody = JSON.parse(response.getContentText()); console.log(`API请求失败,状态码: ${statusCode},错误信息:`, errorBody); return { error: errorBody.error }; } } catch(e) { console.log('请求或解析错误: ' + e); return { error: e.message }; } }
3. 确认用户配置与权限
- 确保多设备用户使用自己的
PROJECT_ID,而非你的项目ID; - 指导用户重新授权应用,确保授权范围覆盖所有Nest设备;
- 检查用户的Google Cloud项目是否已启用Smart Device Management API。
内容的提问来源于stack exchange,提问作者Permafrost
相关产品推荐
相关产品推荐

