Google Apps Script动态上传Drive报错:TypeError非法值修复示例请求
错误修复方案
错误根源
- 前端代码中
saveForm函数里的selectedFile变量未定义,导致รูป(图片)属性值为undefined,触发TypeError - 浏览器的
File对象无法直接通过google.script.run序列化传递给Google Apps Script,必须先上传文件并获取可存储的标识(如Drive文件链接)
修复后的代码示例
前端JavaScript代码
var inputCount = 0; function addInputField() { const dynamicInputs = document.getElementById('dynamicInputs'); const rowContainer = document.createElement('div'); rowContainer.className = 'row g-3'; const col1 = document.createElement('div'); col1.className = 'col-sm'; col1.innerHTML = `<input type="text" class="form-control inp" value="${inputCount + 1}" readonly>`; const col2 = document.createElement('div'); col2.className = 'col-sm-7'; const inputField1 = document.createElement('input'); inputField1.type = 'text'; inputField1.className = 'form-control inp'; inputField1.placeholder = '任务内容'; inputField1.setAttribute('aria-label', '任务内容'); col2.appendChild(inputField1); const col3 = document.createElement('div'); col3.className = 'col-sm'; const inputField2 = document.createElement('input'); inputField2.type = 'file'; inputField2.className = 'form-control inp'; inputField2.placeholder = '图片'; inputField2.setAttribute('aria-label', '图片'); // 给每个文件输入框添加唯一ID,方便后续定位 inputField2.id = `file-${inputCount}`; col3.appendChild(inputField2); const col4 = document.createElement('div'); col4.className = 'col-sm'; const inputField3 = document.createElement('input'); inputField3.type = 'text'; inputField3.className = 'form-control inp'; inputField3.placeholder = '备注'; inputField3.setAttribute('aria-label', '备注'); col4.appendChild(inputField3); rowContainer.id = `input${inputCount}`; rowContainer.appendChild(col1); rowContainer.appendChild(col2); rowContainer.appendChild(col3); rowContainer.appendChild(col4); dynamicInputs.appendChild(rowContainer); inputCount++; document.getElementById('inputCount').innerText = inputCount; } function deleteLastInputField() { if (inputCount > 0) { inputCount--; const dynamicInputs = document.getElementById('dynamicInputs'); const lastRowContainer = document.getElementById(`input${inputCount}`); if (lastRowContainer) { lastRowContainer.remove(); } document.getElementById('inputCount').innerText = inputCount; } } function deleteAllInputFields() { const dynamicInputs = document.getElementById('dynamicInputs'); dynamicInputs.innerHTML = ''; inputCount = 0; document.getElementById('inputCount').innerText = inputCount; } // 异步上传单个文件,返回Drive文件链接 function uploadFile(file) { return new Promise((resolve, reject) => { const formData = new FormData(); formData.append('fileUpload', file); fetch('/exec', { method: 'POST', body: formData }) .then(response => response.text()) .then(data => { resolve(data.startsWith('https://') ? data : '无上传文件'); }) .catch(error => { console.error('上传失败:', error); resolve('上传失败'); }); }); } async function saveForm() { const dynamicInputs = document.getElementById('dynamicInputs'); const rows = dynamicInputs.getElementsByClassName('row g-3'); const tasks = []; // 遍历每一行,先完成文件上传再收集数据 for (let i = 0; i < rows.length; i++) { const row = rows[i]; const columns = row.getElementsByTagName('input'); const fileInput = document.getElementById(`file-${i}`); let fileUrl = '无上传文件'; if (fileInput.files.length > 0) { fileUrl = await uploadFile(fileInput.files[0]); } const task = { ลำดับ: columns[0].value, รายการ: columns[1].value, รูป: fileUrl, หมายเหตุ: columns[3].value, }; tasks.push(task); } // 所有文件上传完成后,提交数据到表格 google.script.run.withSuccessHandler(() => { alert('数据保存成功'); deleteAllInputFields(); }).saveFormData(tasks); }
Google Apps Script后端代码
function saveFormData(formData) { var sheet = SpreadsheetApp.openById('xxx').getActiveSheet(); var newData = []; for (var i = 0; i < formData.length; i++) { var data = formData[i]; // 处理空值,避免写入表格时出错 newData.push([ data['ลำดับ'] || '', data['รายการ'] || '', data['รูป'] || '', data['หมายเหตุ'] || '' ]); } if (newData.length > 0) { sheet.getRange(sheet.getLastRow() + 1, 1, newData.length, newData[0].length).setValues(newData); } } function doPost(e) { var destinationId = 'xxx'; try { if (e.parameter.fileUpload) { var fileBlob = e.parameters.fileUpload[0]; var folder = DriveApp.getFolderById(destinationId); var file = folder.createFile(fileBlob); // 设置文件为公开可查看(可选,根据需求调整权限) file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW); // 返回文件的可访问链接 return ContentService.createTextOutput(file.getUrl()).setMimeType(ContentService.MimeType.TEXT); } else { return ContentService.createTextOutput('未上传任何文件').setMimeType(ContentService.MimeType.TEXT); } } catch (error) { return ContentService.createTextOutput('上传失败: ' + error.message).setMimeType(ContentService.MimeType.TEXT); } }
关键修复说明
- 给每个文件输入框添加唯一ID,确保能准确获取对应行的上传文件
- 新增异步文件上传逻辑,通过
fetch调用doPost接口,获取文件在Google Drive的可访问链接 - 修改
saveForm为异步函数,确保所有文件上传完成后再提交数据到表格 - 后端
doPost调整为返回文件链接,而非单纯的成功提示 - 后端
saveFormData添加空值处理,避免因字段为空导致的写入错误
内容的提问来源于stack exchange,提问作者What
相关产品推荐
相关产品推荐

