【问题标题】:HtmlService not working from doPost() - scriptable async alternative wantedHtmlService 无法从 doPost() 工作 - 需要可编写脚本的异步替代方案
【发布时间】:2013-03-16 03:30:26
【问题描述】:

我想使用带有 HtmlService 的 doPost() 作为异步调度程序来调用其他函数。异步功能对性能很重要——不必同步等待电子表格操作完成,这就是 HtmlService 的用途。 这是我在代码方面的内容:

 function doGet(e) {
      var app = UiApp.createApplication();
  var button = app.createButton('Click Me');
  app.add(button);
  var handler = app.createServerHandler('myClickHandler');
  button.addClickHandler(handler);
  return app;
}

function myClickHandler(){
  sendHttpPostSelf();
}
function doSomething() {
  Logger.log('I was called Now!');
  return;
}
function sendHttpPostSelf() {
  var payload = {
      "name" : "name",
      "comment" : "comment",
      "screenshot" : "screenshot"
  };
  var options = {
      "method" : "post",
      "payload" : payload
    };
var url="https://script.google.com/macros/s/AKfycbzlVoiDQMbLe4yliErDoNub6A0m3tijSfPAUMEBENgIikQnLQ_H/exec";
var resp=UrlFetchApp.fetch(url,options);
Logger.log(resp.getContentText());//.getContent());
} 
function doPost(e){
  var dbg;
  var dbg=true;
  if (dbg==true)for (var i in e.parameter)Logger.log("FormSubmit:doPost "+ i + ": " + e.parameter[i]);
  return HtmlService.createHtmlOutputFromFile("myFile.html");
}

//ANd HERE IS myFile.html
<script>
 function onFailure(error) {
   //alert('Error will Robinson!: '+error.message);
     Logger.log('Error will Robinson!: '+error.message);
  }
  function onSuccess(error) {
    //alert('Gotter Done');
    Logger.log("FormSubmit:doPost",'Gotter Done');
  }
  google.script.run.withSuccessHandler(onSuccess).withFailureHandler(onFailure).doSomething();
</script>

httpPostSelf() 工作正常,doPost() 接收参数正常,但我的问题是 HtmlService.createHtmlOutputFromFile("myFile.html") 没有正确调用 doSomething()? 我只在 Logger.log 中看到很多神秘的 caja 解析
--END OF ORIGINAL QUESTION--

问题添加
亲爱的科里:

感谢您对 doPost() 不处理 HtmlService 和您提出的异步示例的反馈。 你是对的,按钮点击事件是异步的..但我的问题仍然没有答案。澄清, 请允许我进一步详细说明我的问题。我需要做的是对网络应用程序的异步脚本调用(我猜听起来像 AJAX)。除了异步之外,我的示例脚本中的所有内容都有效。然后在我之前的示例中使用替代 URL 来调用单独的 Web 应用程序而不是自我发布:

var url="https://script.google.com/a/macros/commet.com/s/AKfycbwJ4WM3U5POEWF9XqFzjaV_9TiNLspKb7kePAih59vsWllA0og/exec";

异步对性能至关重要,因为我有 2000 多行电子表格代码来执行基本的工作表操作:插入、删除、更新、移动、排序......我将脚本很好地打包到带有方法的对象中。 sheet ops 脚本目前与 Sites 中的 UiApp 脚本打包在一起,可以同步调用。经过多次痛苦的重写,一些更复杂的操作(排序和移动)仍然需要长达 7 秒才能完成。

我想将工作表操作脚本迁移到电子表格 Web 应用程序。工作表操作/Web 应用程序应该可以从我的站点 UiApp 异步调用。例如,当我的站点调用排序时,它会简单地向 Web 应用程序释放带有参数的 sendHttpPost,然后站点将继续完成其 GUI 业务(在客户端进行排序),而无需等待 7 秒的电子表格完成它的排序。哇啦!

带有正确传递参数的 Web 应用程序在我的示例脚本中工作,但不幸的是 UrlFetchApp.fetch(对我而言)是同步的。这就是我尝试异步 HtmlService-google.script.run 的原因。我尝试使用 HtmlService 作为 Web 应用程序调用 doGet(),但使用 UrlFetchApp.fetch 也不起作用。 HtmlService 作为 Web 应用程序工作的唯一方法是从带有表单提交的按钮调用时......我需要一个可编写脚本的界面。

UrlFetchApp.fetch - HtmlService 的任何可编写脚本的替代方案?

评论 HtmlService Web 应用访问
以下是 HtmlService 在 Web 应用中工作时的测试结果:
doPost()
- 使用 FormPanel 中的提交按钮提交时有效
- 使用 UrlFetchApp.fetch 提交时不起作用(脚本访问需要)
评论:任何让 doPost() 与 UrlFetchApp.fetch 一起工作的方法都非常适合编程表单!

doGet()
- 从浏览器 url 工作
- 使用 UrlFetchApp.fetch 提交时不起作用(脚本访问需要)
如果有任何不准确的地方,请回复脚本示例。我需要的是 UrlFetchApp.fetch 脚本访问。

【问题讨论】:

  • HtmlService 页面可以对任何脚本函数进行可编写脚本的异步调用,而无需按下按钮...只需编写您想要的任何 JavaScript 并使用 google.script.run,它是异步的。您将需要用户打开脚本的浏览器窗口
  • 如果您有一个可用的脚本接口,请解释并给出一个示例。可编写脚本的接口意味着此函数:function testAsyncHtmlService(){ return HtmlService.createHtmlOutputFromFile("myFile.html"); } 可以通过以下调用从任何其他函数调用:testAsyncHtmlService(); 这不起作用...调用 HtmlService 的唯一方法是打开应用程序使用 doGet()。在 Web 应用程序中,甚至 doGet() 也不起作用。
  • 您只能从 doGet 返回一个 HtmlOutput,但您可以从任何 google.script.run 函数调用返回一个字符串,因此您可以返回 HtmlOutput.getContent()。
  • 当然,我很想找到一种调用异步 google.script.run.function 的方法。有没有办法从 UiApp 中的事件处理程序调用 google.script.run.function?我的应用程序在使用 UiApp 时卡住了。或者,我会编写一个 webapp 来支持使用 HtmlService 的调用 - google.script.run.function 但 webapp 尚不支持 HtmlService(既不支持 doGet() 也不支持 doPost() - 我将为 HtmlService webapp 提交新功能请求也支持)。谢谢康梅特
  • Webapps 在 doGet 和 doPost 中都支持 HtmlService。从这些 cmets 和其他人看来,在我看来,您确实没有阅读过 HtmlService 文档;也许再看看它?

标签: google-apps-script


【解决方案1】:

您正在尝试通过 doPost 从 UiApp 联系 HtmlService,这将无法正常工作。 UiApp 的 doPost 只能接受 UiApp 响应,而 HtmlService 甚至不使用 doPost - 它只使用 google.script.run 语法。您看到的是客户端上的 UiApp 代码被 HtmlService 类型的响应完全混淆了。

但我认为您可能对这两种服务的工作方式感到困惑,因为 UiApp ServerHandler 回调和 HtmlService google.script.run 都异步调用服务器脚本,而无需您执行任何自定义或棘手的操作。无需混合和匹配两者,也无需涉及 doPost - 它专门用于通过 UiApp 上传文件(这就是 HtmlService 不支持它的原因,因为它具有更简单的上传文件语法) .

这是 UiApp 中的异步调度程序:

function doGet() {
  var app = UiApp.createApplication();
  app.add(app.createButton("run foo", app.createServerHandler("foo")));
  app.add(app.createButton("run bar", app.createServerHandler("bar")));
  return app;
}
function foo() { Logger.log("ran foo!");  }
function bar() { Logger.log("ran bar!");  }

这里的HtmlService也是一样的:

function doGet() {
  return HtmlService.createHtmlOutput(
      "<button onclick='google.script.run.foo()'>run foo</button>" +
      "<button onclick='google.script.run.bar()'>run bar</button>"); 
}
function foo() { Logger.log("ran foo!");  }
function bar() { Logger.log("ran bar!");  }

要回答下面的评论,在 UiApp 中,您可以通过 addCallbackElement 将值从客户端发送到服务器。在 HtmlService 中,您只需将参数添加到您的服务器函数:

function doGet() {
  return HtmlService.createHtmlOutput(
      "<button onclick='var foo = document.getElementById(\'myTextBox\').value; google.script.run.foo(123, foo)'>run foo</button>"
}
function foo(x, y) { Logger.log("ran foo with params " + x + " and + "y");  }

这应该记录“run foo with params 123 and contents of myTextBox”。您应该能够从那里进行概括(我建议您也阅读用户指南。)

【讨论】:

  • 谢谢Corey - 请参阅上面的问题补充说明
  • 你能在这个例子中为 HtmlService 显示 .addCallbackElement(myTextBox) 的等价物吗?
【解决方案2】:

当您在自己制作的 HtmlTemplates 中运行脚本时,它们无法访问 Apps 脚本库(但您可以调用您的 Apps 脚本函数)。例如,您不能从 Html 页面调用 Logger.log()。你应该使用console.log()。这将登录到您的 Web 控制台。 (Ctrl+Shift+J 在 Chrome 中)。

【讨论】:

    猜你喜欢
    • 2019-08-08
    • 2020-10-17
    • 2017-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多