登录后无法跳转页面:Sandbox导航权限与用户激活问题
解决Google Apps Script中自动跳转的沙箱导航错误
登录后尝试自动导航到目标页面时触发以下错误:
错误信息:
来自URL为'https://n-x4qqieogl32dh7vitgxnysfogdq2h5ccinv5p6a-0lu-script.googleusercontent.com/userCodeAppPanel'的框架,尝试对源为'https://script.google.com'的框架发起导航,存在不安全操作。尝试导航顶级窗口的框架已被沙箱化,且带有'allow-top-navigation-by-user-activation'标记,但无用户激活(即手势)。
相关代码:
function ModelViewer(token) { if (!token) { console.log("No token found"); return; } // Fetch the URL dynamically google.script.run.withSuccessHandler(function (appUrl) { console.log("Fetched URL:", appUrl); google.script.run.withSuccessHandler(function (isValid) { if (isValid) { console.log("isValid it is!") console.log("Token", token); const link = document.createElement('a'); link.href = `${appUrl}?page=Models&token=${token}`; link.id = 'linkURL'; document.body.appendChild(link); document.getElementById('linkURL').click(); } else { console.log("isValid",isValid); console.log("Token", token); console.log("Invalid token. Redirecting to SignIn."); showNotification("Session expired. Please sign in again.", "error"); } }).validateToken(token); }).getAppUrl(); // Call the server-side function to get the URL }
问题原因
代码中通过link.click()自动触发跳转的操作,不符合Google Apps Script客户端沙箱的安全规则:顶级窗口导航必须由用户主动交互(如点击按钮、链接等手势操作)触发,异步回调中的自动点击不属于用户激活行为,因此被浏览器拦截。
修复方案
方案1:引导用户主动点击跳转
将自动跳转改为显示交互按钮,让用户手动完成导航:
function ModelViewer(token) { if (!token) { console.log("No token found"); return; } google.script.run.withSuccessHandler(function (appUrl) { console.log("Fetched URL:", appUrl); google.script.run.withSuccessHandler(function (isValid) { if (isValid) { console.log("isValid it is!") console.log("Token", token); // 创建跳转按钮 const jumpBtn = document.createElement('button'); jumpBtn.textContent = '进入模型页面'; jumpBtn.style.padding = '8px 16px'; jumpBtn.addEventListener('click', () => { window.location.href = `${appUrl}?page=Models&token=${token}`; }); document.body.appendChild(jumpBtn); } else { console.log("isValid",isValid); console.log("Token", token); console.log("Invalid token. Redirecting to SignIn."); showNotification("Session expired. Please sign in again.", "error"); } }).validateToken(token); }).getAppUrl(); }
方案2:保留用户初始激活上下文
如果ModelViewer本身由用户点击操作触发(比如登录按钮),可以将异步操作封装为Promise,确保跳转在用户初始点击的事件链中完成:
// 假设登录按钮ID为loginBtn document.getElementById('loginBtn').addEventListener('click', async function() { const token = await getLoginToken(); // 替换为实际获取token的逻辑 if (!token) { console.log("No token found"); return; } // 用Promise封装google.script.run的异步操作 const getAppUrl = () => new Promise(resolve => google.script.run.withSuccessHandler(resolve).getAppUrl()); const validateToken = (t) => new Promise(resolve => google.script.run.withSuccessHandler(resolve).validateToken(t)); const appUrl = await getAppUrl(); const isValid = await validateToken(token); if (isValid) { // 此时仍处于用户点击的激活状态,直接跳转不会被拦截 window.location.href = `${appUrl}?page=Models&token=${token}`; } else { showNotification("Session expired. Please sign in again.", "error"); } });
内容的提问来源于stack exchange,提问作者Dhruv
相关产品推荐
相关产品推荐

