加载 jQuery 等外部脚本时出现问题
从今天早上开始,我在使用 Apps Script 部署网络应用程序时遇到了一个问题,这个程序以前运行得很好。当然,没有进行任何更改来证明这个问题是合理的。
外部脚本不会从 HTML 端加载,并且控制台中会出现新错误。
为了有一个可重现的例子:
Code.gs
function doGet() {
var template = HtmlService.createTemplateFromFile('index');
return template.evaluate()
.setTitle('TEST')
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
}
index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<div id="title">Hello</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>
window.onload = function() {
console.log('loaded');
console.log($('#title').html());
}
</script>
</html>
控制台中的结果:
[ERROR] This document requires 'TrustedHTML' assignment. (jquery.min.js:2)
[ERROR] Uncaught TypeError: Failed to set the 'innerHTML' property on 'Element': This document requires 'TrustedHTML' assignment. (jquery.min.js:2)
[LOG] loaded
[ERROR] Uncaught ReferenceError: $ is not defined
源问题似乎是 <script src=''
加载 jQuery。但我没有注意到 Google 提供任何故障排除,这是对 Apps 脚本的新限制吗?
我发现这个问题似乎与 Google 最近对内容安全策略 (CSP) 的更改有关,特别是影响了 AppScript 中 jQuery 的使用。此问题一直影响着众多开发者,您可以在此处的 Google 问题跟踪器上找到更多详细信息和正在进行的讨论:Google问题跟踪器 - CSP 和 jQuery 问题。
根据我的发现,这个问题似乎是基于 Chromium 的浏览器特有的。在 Chrome 和 Edge 等环境中,包括它们的隐身模式,jQuery 无法正常运行。不过,我发现 Firefox 并没有遇到这个问题,并且可以按预期工作。
这种特定于浏览器的行为建议了一种解决方法:如果您在基于 Chromium 的浏览器上的 AppScript 项目中遇到 jQuery 问题,请尝试切换到 Firefox 作为临时解决方案,直到 Google 实现更永久的修复。
编辑:找到以下解决方法。将其放在 HTML <head>
的最顶部。
<script>
if (window.trustedTypes && window.trustedTypes.createPolicy) {
window.trustedTypes.createPolicy('default', {
createHTML: string => string,
createScriptURL: string => string,
createScript: string => string,
});
}
</script>
根据 Google 问题跟踪器,这里有一个解决方法,可以将HTML<head>
:
<script>
if (window.trustedTypes && window.trustedTypes.createPolicy) {
window.trustedTypes.createPolicy('default', {
createHTML: string => string,
createScriptURL: string => string,
createScript: string => string,
});
}
</script>
您的错误表明该网址不符合您的 CSP 。您没有更改您的代码 - 是的,但是您的服务器有一个 CSP 规则集,并且根据该规则,jQuery 被拒绝。您需要查看主请求的响应标头以及 HTML 中的元标记,以了解您的 CSP 实际是什么。然后找到它的定义位置(在服务器设置或元标记或一些自定义代码中)并进行调整,以便允许使用 jQuery。
或者,您可以在本地下载 jquery 脚本并在本地链接它。
编辑
我进一步了解了这一点,特别是在 https://developer.mozilla.org/en-US/docs/Web/API/TrustedHTML
这特别有趣,受到上面链接的启发:
const escapeHTMLPolicy = trustedTypes.createPolicy("myEscapePolicy", {
createHTML: (string) => string.replace(/</g, "<"),
});
let el = document.getElementById("myDiv");
const escaped = escapeHTMLPolicy.createHTML("<img src=x onerror=alert(1)>");
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped;
当然,具有以下 HTML
<div id="myDiv"></div>
我测试了上面的内容,结果在 FireFox 中不起作用,在 Chrome 中起作用。
因此,您需要查看是否完全支持trustedTypes
:
if (typeof trustedTypes === "undefined") {
alert("Trusted types are not supported");
} else {
alert("Trusted types are supported");
}
现在,我建议您可以创建一个函数,在内部检查 trustedTypes
是否受支持,如果支持,则创建一个策略。否则,只需创建一个具有方法名称的函数。然后,您可以在任何浏览器中调用该函数,而不必担心哪里支持它,哪里不支持它:
function getEscapeHTMLPolicy() {
if (typeof trustedTypes === "undefined") {
return {
createHTML: (string) => string.replace(/</g, "<"),
}
} else {
return escapeHTMLPolicy = trustedTypes.createPolicy("myEscapePolicy", {
createHTML: (string) => string.replace(/</g, "<"),
})
}
}
let escPol = getEscapeHTMLPolicy();
window.addEventListener("load", function() {
document.getElementById("mydiv").innerHTML = escPol.createHTML(`<p>foo</p>`);
});
<div id="mydiv"></div>