基于Google Sheet的Apps Script Web App提交后返回403禁止错误
解决Google Apps Script Web App提交后返回403 Forbidden且不显示成功消息的问题
我用Google Sheet的Apps Script搭建了一个Web App,它能获取用户位置并成功向表格插入新行,但提交表单完成插入后,不会返回成功消息,反而弹出Forbidden Error 403。我已经清除浏览器缓存、尝试过不同浏览器和设备,问题依然存在。
现有GS文件代码
const sheetName = 'Sheet1' const scriptProp = PropertiesService.getScriptProperties() function initialSetup () { const activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet() scriptProp.setProperty('key', activeSpreadsheet.getId()) } function doPost (e) { const lock = LockService.getScriptLock() lock.tryLock(10000) try { const doc = SpreadsheetApp.openById(scriptProp.getProperty('key')) const sheet = doc.getSheetByName(sheetName) const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0] const nextRow = sheet.getLastRow() + 1 const newRow = headers.map(function(header) { return header === 'Date' ? 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() } } function doGet(e) { const userEmail = Session.getActiveUser().getEmail(); var htmlOutput = HtmlService.createTemplateFromFile('Form'); htmlOutput.email = userEmail; return htmlOutput.evaluate(); }
现有HTML文件代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-16"> <title>Google Sheet Form</title> <style> form {... </style> <script> function getLocation() { // Check if the browser supports geolocation if (navigator.geolocation) { // Get the current position of the user navigator.geolocation.getCurrentPosition(showPosition); } else { alert("Geolocation is not supported by this browser."); } } function showPosition(position) { // Get the latitude and longitude values from the geolocation data var latitude = position.coords.latitude; var longitude = position.coords.longitude; // Populate the input field with the latitude and longitude values document.getElementById("Latitude").value = latitude; document.getElementById("Longitude").value = longitude; } // Function to show the success message function showSuccessMessage() { const successMessage = document.getElementById('successMessage'); successMessage.style.display = 'block'; } const responseText = '{"result": "success"}'; // Replace this with the actual response const response = JSON.parse(responseText); if (response.result === 'success') { // Display the success message to the user showSuccessMessage(); } </script> </head> <body> <form action="..." method="post"> <span>Logged In: <?= email ?></span> <p> <input size="20" name="Email" type="email" placeholder="Email" required value="<?= email ?>" readonly> </p> <p> <input size="20" type="text" id="Latitude" name="Latitude" placeholder="Latitude"readonly> </p> <p> <input size="20" type="text" id="Longitude" name="Longitude" placeholder="Longitude"readonly> </p> <p> <button size="20" type="button" onclick="getLocation()">Get Location</button> </p> <p> <button size="20" type="submit">Sign In/Sign Out</button> </p> <!-- Add a div to display the success message --> <div id="successMessage" style="display: none;">Form submitted successfully!</div> <!-- Add a div to display the error message --> <div id="errorMessage" style="display: none;">An error occurred. Please try again.</div> </form> </body> </html>
问题根源分析
- 403 Forbidden错误:HTML表单的
action属性是占位符"...",未填写正确的Web App部署URL,导致提交请求地址无效;同时Web App部署权限可能未配置正确,拒绝了外部请求。 - 成功消息不显示:当前HTML硬编码了模拟响应,未实际接收
doPost返回的真实数据,且表单默认同步提交会直接跳转页面,无法执行后续消息显示逻辑。
修复步骤
1. 修正Web App部署配置
重新部署Web App,确保:
- 执行权限选择**「任何人,甚至匿名用户」(无需登录限制)或「任何人」**(需用户登录Google账号)
- 复制部署后生成的Web App URL,后续用于表单提交地址
2. 重写HTML实现异步提交与响应处理
将表单改为AJAX异步提交,避免页面跳转,同时接收doPost返回的JSON响应并显示对应消息:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Google Sheet Form</title> <style> form { margin: 20px; padding: 20px; border: 1px solid #ccc; border-radius: 8px; } #successMessage { color: green; margin-top: 15px; } #errorMessage { color: red; margin-top: 15px; } </style> <script> function getLocation() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(showPosition); } else { alert("当前浏览器不支持地理定位"); } } function showPosition(position) { document.getElementById("Latitude").value = position.coords.latitude; document.getElementById("Longitude").value = position.coords.longitude; } // 处理表单提交 function handleSubmit(event) { event.preventDefault(); const formData = new FormData(event.target); // 替换为你的Web App部署URL const webAppUrl = "你的Web App部署URL"; fetch(webAppUrl, { method: 'POST', body: formData }) .then(res => res.json()) .then(data => { const successEl = document.getElementById('successMessage'); const errorEl = document.getElementById('errorMessage'); if (data.result === 'success') { successEl.style.display = 'block'; errorEl.style.display = 'none'; event.target.reset(); } else { errorEl.style.display = 'block'; successEl.style.display = 'none'; console.error('提交失败:', data.error); } }) .catch(err => { document.getElementById('errorMessage').style.display = 'block'; document.getElementById('successMessage').style.display = 'none'; console.error('请求异常:', err); }); } // 绑定提交事件 document.addEventListener('DOMContentLoaded', () => { document.querySelector('form').addEventListener('submit', handleSubmit); }); </script> </head> <body> <form> <span>已登录: <?= email ?></span> <p> <input size="20" name="Email" type="email" placeholder="邮箱" required value="<?= email ?>" readonly> </p> <p> <input size="20" type="text" id="Latitude" name="Latitude" placeholder="纬度" readonly> </p> <p> <input size="20" type="text" id="Longitude" name="Longitude" placeholder="经度" readonly> </p> <p> <button size="20" type="button" onclick="getLocation()">获取位置</button> </p> <p> <button size="20" type="submit">签到/签退</button> </p> <div id="successMessage" style="display: none;">表单提交成功!</div> <div id="errorMessage" style="display: none;">提交失败,请重试。</div> </form> </body> </html>
3. 优化GS代码(可选)
添加必填字段验证,避免空数据提交:
// 在doPost的try块开头添加 if (!e.parameter.Email || !e.parameter.Latitude || !e.parameter.Longitude) { throw new Error('缺少必填字段:邮箱/纬度/经度'); }
注意事项
- 每次修改代码后,必须重新部署Web App并更新HTML中的
webAppUrl(如果部署生成了新URL) - 若需限制特定用户访问,可在
doPost中添加邮箱白名单验证逻辑
内容的提问来源于stack exchange,提问作者Pieter le Roux
相关产品推荐
相关产品推荐

