Google Apps Script WebApp多用户并发时UserProperty身份数据被覆盖问题求助
问题根源
你遇到的覆盖问题是Google Apps Script的特性导致的:当WebApp设置为以脚本所有者身份运行时,所有用户触发的脚本执行环境都归属所有者,UserProperties本质是按执行环境的用户隔离的,所以所有用户访问的都是同一个UserProperties实例,用固定key存储自然会互相覆盖。
可行解决方案
首先推荐最稳妥的无状态方案,完全不需要依赖服务端存储用户身份:
方案1:前端传递身份参数(推荐)
核心逻辑是:在doPost拿到用户邮箱后,直接注入到返回的HTML模板中,前端存储后在每次调用google.script.run时主动将邮箱作为参数传递给后端,完全抛弃UserProperties存储。
步骤1:修改doPost逻辑,移除属性存储改为注入模板
function doPost(e) { var postContents = e.postData.contents.split("&"); var postSplit = postContents[16].split("="); var activeUserEmail = postSplit[1].replace("%40", "@"); // 删掉原有的userProperties.setProperty行,不需要服务端存储 if (activeUserEmail[2] == "s" || activeUserEmail[2] == ".") { console.log("Redirecting to Student: " + activeUserEmail); const template = HtmlService.createTemplateFromFile('student_form'); // 将用户邮箱注入模板变量 template.activeUserEmail = activeUserEmail; return template.evaluate() .addMetaTag('viewport', 'width=device-width, initial-scale=1') .setSandboxMode(HtmlService.SandboxMode.IFRAME) .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL); } }
步骤2:修改前端HTML代码,存储身份并传递参数
在你的student_form.html中加入以下逻辑:
<script> // 读取模板注入的用户邮箱,存在前端全局变量 const CURRENT_USER_EMAIL = "<?= activeUserEmail ?>"; // 调用后端接口时主动传递邮箱参数 function loadFormData() { google.script.run .withSuccessHandler(renderForm) // 替换为你自己的成功回调函数 .getData(CURRENT_USER_EMAIL); } </script>
步骤3:修改getData函数,接收前端传递的参数
// 新增参数接收前端传的用户邮箱 function getData(activeUserEmail) { console.log("getData User: " + activeUserEmail); try { if (activeUserEmail != "") { var userResults = teachersSheet.filter(function (row) { return row[0] == activeUserEmail; }); } else { var userResults = "No User Email" } var userDepartment = userResults[0][2]; if (userDepartment == "Admin") { var data = questionsSheet.getDisplayValues().filter(function (row) { return row[1] != "" && row[0] != "ID"; }); } else { var data = questionsSheet.getDisplayValues().filter(function (row) { return row[3] == userDepartment && row[9] == "FALSE" && row[1] != ""; }); }; var data = [userResults, data]; console.log(data); return data; } catch (e) { console.log(e); } }
可选安全增强
如果担心前端篡改邮箱冒充其他用户,可以增加签名校验:
- 在脚本中定义一个仅你知道的密钥:
const SECRET_KEY = "自定义的随机字符串" doPost时给邮箱生成HMAC签名,和邮箱一起注入模板- 前端调用接口时同时传递邮箱和签名
- 后端校验签名合法性,确认邮箱未被篡改
其他可选方案
如果确实需要服务端临时存储用户身份,可以使用以下两种方案:
- 带唯一标识的
UserProperties存储:将用户邮箱作为key的一部分,比如user_email_${activeUserEmail},避免不同用户共用同一个key,需要定期清理过期的属性避免存储超限 CacheService缓存:同样用用户唯一标识作为key前缀,设置合理的过期时间(最长6小时),适合短期存储场景
内容的提问来源于stack exchange,提问作者Sved
相关产品推荐
相关产品推荐

