我正在制作一个 Google 表格插件。该插件打开一个无模式对话框,其中托管 www.myfrontend.com,它使用 www.mybackend.com 作为后端。
要实现这一点,一种方法是使用
iframe
,如下所示:
var htmlOutput = HtmlService
.createHtmlOutput('<iframe src="https://www.myfrontend.com/#/home" style="width: 100%; height: 800px; border: none;"></iframe>'
.setWidth(600)
.setHeight(800);
SpreadsheetApp.getUi().showModelessDialog(htmlOutput, 'My add-on');
通过这种方法,myfrontend.com 可以显示在对话框中,并且调用 mybackend.com 没有任何问题。然而,myfrontend.com 中似乎没有
google
;我无法在 myfrontend.com 中拨打 google.script.run.withSuccessHandler(res).withFailureHandler(rej)...
。因此,myfrontend.com 无法与 Google Sheet 通信。
另一种方法是在 Apps 脚本中拥有另一个类似
production.html
的文件,并按如下方式使用它:
var htmlOutput = HtmlService
.createHtmlOutputFromFile('production')
.setWidth(600)
.setHeight(800);
SpreadsheetApp.getUi().showModelessDialog(htmlOutput, 'My add-on');
production.html
复制自 myfrontend.com 的 build/index.html
,并稍作修改:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<base href="https://www.myfrontend.com/">
<link rel="icon" href="/favicon.ico"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="theme-color" content="#ffffff"/>
<meta name="description" content="Web site created using create-react-app"/>
<link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/>
<meta charset="utf-8"/><meta charset="UTF-8"/><meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
<title>myApp</title>
<script>window.location.hash = "#/home"</script>
... ...
通过这种方法,myfrontend.com 可以显示在对话框中,并且看起来
google
和 google.script.run
在 myfrontend.com 中可用。但是,当我们登录 myfrontend.com 时,浏览器返回 CORS 错误:
[Error] Origin https://n-5fydpzckmar5yncflnjytuyfcusdcfogmgc2eti-1lu-script.googleusercontent.com is not allowed by Access-Control-Allow-Origin. Status code: 204
[Error] XMLHttpRequest cannot load https://www.mybackend.com/httpOnly/signin due to access control checks.
在
www.backend.com的
app.js
中,我已经启用了CORS,如下,但错误仍然存在:
app.use(cors({
origin: [/\.mybackend\.com$/, /\.myfrontend\.com$/, /localhost(:[0-9]*)?$/, /\.live\.com$/, "https://onedrive.live.com", /https:\/\/[\w-]+\.script\.googleusercontent\.com/],
credentials: true,
}));
那么有谁知道在无模式对话框中托管网站的正确方法是什么,确保通过
google.script.run
与谷歌表格进行通信并与后端进行通信?
window.postMessage
进行交流。
<script>
window.addEventListener('message',e =>{
if(e.origin !== "https://www.myfrontend.com") return;
const frontEndWindow = e.source;
const data = JSON.parse(e.data);
const {funcToRun, args} = data;
//TODO: SECURITY:
// Check syntax of funcToRun, args
// Check funcToRun against list of available functions
// Check args are as expected
//TODO Add failureHandler
google.script.run.withSuccessHandler(res => {
console.log(res);
const iframeWindow = document.querySelector('#myFrame').contentWindow;
iframeWindow.postMessage(({type:'success',response:res}),"https://www.myfrontend.com")
})[funcToRun](...args)
},false)
</script>
<iframe
id="myFrame"
src="https://www.myfrontend.com/#/home"
style="width: 100%; height: 800px; border: none"
</iframe>
var htmlOutput = HtmlService
.createHtmlOutputFromFile('modal.html'
.setWidth(600)
.setHeight(800);
SpreadsheetApp.getUi().showModelessDialog(htmlOutput, 'My add-on');
window.parent.postMessage(
(JSON.stringify({funcToRun: 'getData', args:[1,2]})),
'https://n-5fydpzckmar5yncflnjytuyfcusdcfogmgc2eti-1lu-script.googleusercontent.com')