如何防止Google Sheets中因页面重载产生的重复数据提交
解决Google Sheets重复提交数据的两种方案
方案一:前端拦截重复请求
在页面加载时先校验当前URL参数是否已提交过,通过本地存储记录已提交的参数标识,避免重复发起请求。
修改后的JavaScript代码:
const queryParameters = Object.fromEntries(new URLSearchParams(window.location.search)); const scriptURL = 'https://script.google.com/macros/s/example'; // 生成当前参数的唯一标识(替换成你实际的两个参数名,比如'paramA'和'paramB') const paramKey = `${queryParameters.paramA}_${queryParameters.paramB}`; // 用sessionStorage,关闭页面后失效;需长期保留则换成localStorage const hasSubmitted = sessionStorage.getItem(paramKey); if (!hasSubmitted) { const data = new FormData(); Object.entries(queryParameters).forEach(e => data.append(...e)); fetch(scriptURL, { method: 'POST', body: data}) .then(response => { console.log('Success!', response); // 提交成功后标记已提交 sessionStorage.setItem(paramKey, 'true'); }) .catch(error => console.error('Error!', error.message)); }
方案二:后端Google Script校验重复数据
在接收POST请求时,先检查表格中是否已有相同参数的条目,仅当不存在时才插入新行,作为兜底校验。
修改后的Google Script代码:
var sheetName = 'Sheet1' var scriptProp = PropertiesService.getScriptProperties() function intialSetup () { var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet() scriptProp.setProperty('key', activeSpreadsheet.getId()) } function doPost (e) { var lock = LockService.getScriptLock() lock.tryLock(10000) try { var doc = SpreadsheetApp.openById(scriptProp.getProperty('key')) var sheet = doc.getSheetByName(sheetName) var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0] // 获取当前提交的两个参数(替换成你实际的参数名) const currentParamA = e.parameter.paramA; const currentParamB = e.parameter.paramB; // 用TextFinder优化查询效率(避免遍历所有行) const paramAIndex = headers.indexOf('paramA') + 1; // 表格列索引从1开始 const paramBIndex = headers.indexOf('paramB') + 1; // 先找所有匹配paramA的行,再检查这些行的paramB是否一致 const paramAFinder = sheet.getRange(2, paramAIndex, sheet.getLastRow()-1) .createTextFinder(currentParamA) .matchEntireCell(true); const matchingRows = paramAFinder.findAll().map(cell => cell.getRow()); const isDuplicate = matchingRows.some(row => sheet.getRange(row, paramBIndex).getValue() === currentParamB); if (isDuplicate) { return ContentService .createTextOutput(JSON.stringify({ 'result': 'duplicate', 'message': '数据已存在' })) .setMimeType(ContentService.MimeType.JSON); } // 无重复则插入新行 var nextRow = sheet.getLastRow() + 1 var newRow = headers.map(function(header) { return header === 'timestamp' ? new Date() : e.parameter[header] }) sheet.getRange(nextRow, 1, 1, newRow.length).setValues([newRow]) return ContentService .createTextOutput(JSON.stringify({ 'result': 'success', 'row': nextRow })) .setMimeType(ContentService.MimeType.JSON) } catch (e) { return ContentService .createTextOutput(JSON.stringify({ 'result': 'error', 'error': e })) .setMimeType(ContentService.MimeType.JSON) } finally { lock.releaseLock() } }
注意事项
- 两种方案中的参数名(如
paramA、paramB)需替换成你实际使用的参数标识 - 若表格数据量极小,后端方案也可改用遍历行的方式,但TextFinder在数据量大时效率更高
内容的提问来源于stack exchange,提问作者jparko
相关产品推荐
相关产品推荐

