Google Apps 脚本文件上传(通过 HTML 表单)仅在脚本“绑定”时有效(测试独立脚本时,HTTP 403 错误)

Posted

技术标签:

【中文标题】Google Apps 脚本文件上传(通过 HTML 表单)仅在脚本“绑定”时有效(测试独立脚本时,HTTP 403 错误)【英文标题】:Google Apps Script file upload (by HTML form) only works when script is "bound" (when standalone script tested, HTTP 403 error) 【发布时间】:2017-08-27 11:43:07 【问题描述】:

要将本地文件上传到 Google 云端硬盘,我有一个 html <form></form>(参见下面的代码),它以模式显示在用户打开的 Google 表格上方。 HTML 表单中包含 <input type="file" name="...">,当我单击发送表单对象时,我成功上传了文件 如果,此 Google Apps 脚本“绑定”到特定的表格文件(使用Tools > Script Editor... 菜单编写)。

如果我将脚本保存为独立脚本,然后在我选择的表格文件上对其进行测试(已安装并启用),则 <form> 的 onclick 操作和调用 google.script.run.aServerFunction(...) 的尝试会导致 @987654329 @。为了澄清这一点,我通过创建一个独立的脚本并在表格文件上对其进行测试:https://developers.google.com/apps-script/add-ons/#understand_the_development_cycle。在早期的代码迭代中,我也得到了某种授权 scriptError。私下发布脚本以供测试人员在工作表上使用时出现同样的错误。不幸的是,我认为我需要它作为一个独立的脚本,以后可以作为附加组件发布——而不是使用Tools > Script Editor... 菜单绑定到单个工作表的辅助脚本。

我在 Stack Overflow 上的第一篇文章 - 请原谅任何行话或排版错误,谢谢!

HTML 改编自教程:

    <!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
    </script>
    <script>
        function failed(event) 
          $("div.response").text(event);
          //google.script.run.selectStuff();
          //google.script.host.close();
        
      </script>
  </head>
  <body>
    <form id="myForm">

    <label>Your Name</label>
    <input type="text" name="myName">

    <label>Pick a file</label>
    <input type="file" name="myFile">

    <input type="submit" value="Upload File" 
               onclick="google.script.run.withFailureHandler(failed)
                        .uploadFiles(this.parentNode);
                        return false;">
</form>
<div class="response"></div>
  </body>

</html>

在code.gs中:

function uploadFiles(formObject) 
  /*var sheet1 = SpreadsheetApp.getActiveSheet();
  sheet1.setActiveRange(sheet1.getRange(2, 2, 4, 4));

  var formBlob = formObject.myFile;
  var driveFile = DriveApp.createFile(formBlob);
  driveFile.addEditor("...");
  SpreadsheetApp.getActive().toast(driveFile.getUrl());
  sheet1.getRange(1,1,1,1).setValue(driveFile.getUrl());
  return driveFile.getUrl();*/

  return "it worked";

【问题讨论】:

您不能在未绑定到电子表格的脚本中使用getActiveSheet()。您有:var sheet1 = SpreadsheetApp.getActiveSheet(); 您需要按 ID 获取电子表格文件。除非这是唯一可用的东西,否则通过 URL 获取它是没有意义的。 您能否解释一下您是如何做到这一点的:“如果我将脚本保存为独立脚本,然后在我选择的表格文件上对其进行测试(安装并启用)。”您是否正在尝试添加工作表?如果您正在创建一个独立的脚本,您是否使用 doGet() 来提供 HTML 页面? @SandyGood 非常感谢这一点。但没有修复“NetworkError:由于 HTTP 403 导致的连接失败”——HTML 的 onclick 中的失败处理程序仍然会触发。我已经更改了上面的代码以删除 getActiveSheet() @JackBrown 我正在尝试创建一个工作表插件。它在这里说我可以通过编写一个独立的脚本来做到这一点,该脚本稍后会在特定的表格上进行测试,并且可以作为附加组件发布:(developers.google.com/apps-script/add-ons/…)。我正在使用 (developers.google.com/apps-script/add-ons/test#top_of_page) 处的说明来“验证以独立脚本编写的附加组件在应用于工作表时是否起作用......”。我也私下发表过。没有使用 doGet() - 我使用 SpreadsheetApp.getUi().showModalDialog(htmlOutputObj, 'Upload Student Roster'); 由于您使用脚本作为表单添加,您可以使用“getactive()”来获取电子表格。并且您在安装和启用时运行测试插件,因此授权应该不是问题。我在这里不知所措:/。我会试一试,看看我是否可以重现错误,并希望其他人能给你比我更好的建议。 【参考方案1】:

我相信您收到 HTTP 403 错误的原因是因为表单 DOM 元素是表单插件中 google.script.run.myfunction(...) 中的非法参数。尽管它们在此处被提及为合法参数here,但我认为附加组件具有无法传递任何类型的 DOM 元素的附加限制。

我想出的解决方案是使用原生 javascript 中的 Filereader.readAsDataUrl() 函数将上传的文件转换为 base64 编码字符串,并将字符串传递给谷歌脚本并将其转换回要上传到谷歌驱动器的文件。 base64 编码字符串的开头是这样的:

数据:应用程序/pdf;base64,JVBERi0xLjMKJcTl8uXrp/Og0MTG....

气体

function uploadFiles(formObject) 
  // extract contentType from the encoded string 
  var contentType = formObject.split(",")[0].split(";")[0].split(":")[1]
  // New Blob(data,contentType,name)
  // Use base64decode to get file data
  var blob = Utilities.newBlob(Utilities.base64Decode(formObject.split(",")[1]), contentType, "trial")
  var driveFile = DriveApp.getFolderById("your Folder ID here").createFile(blob);
  //return contentType, can be anything you like
  return blob.getContentType()

HTML 脚本

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
    </script>

  </head>
  <body>
    <form id="myForm">

    <label>Your Name</label>
    <input type="text" name="myName">

    <label>Pick a file</label>
    <input type="file" id = "filemy" name="myFile">

    <input type="button" value="Upload File" 
               onclick="upload(this.parentNode)">
</form>
<div class="response"></div>
  </body>
  <script>
        function failed(event) 
          $("div.response").text(event);
          //google.script.run.selectStuff();
          //google.script.host.close();
        

        function upload(frmData)
        var file = document.getElementById("filemy").files[0]
        var reader = new FileReader()
        //reader.onload is triggered when readAsDataURL is has finished encoding
        //This will take a bit of time, so be patient
        reader.onload = function(event) 
        // The file's text will be printed here
        console.log("File being Uploaded")
        //console.log(event.target.result)
        google.script.run.withFailureHandler(failed).withSuccessHandler(failed)
                        .uploadFiles(event.target.result);
        ;

        reader.readAsDataURL(file);
        console.log(reader.result)
        
      </script>

</html>

最后说明:我没有对代码进行广泛的测试,我已经让它与一个 pdf 文件和一个最大大小为 2.6MB 的图像/png 文件一起工作。因此,请先尝试这两种文件类型,然后再继续其他类型的文件! 此外,文件确实需要一段时间才能上传,所以请耐心等待(~5-10 秒)。尤其是因为没有进度条显示上传进度,感觉就像什么都没有发生。

希望对您有所帮助!

【讨论】:

我明天会试试这个——但是你得到了一个 pdf 和 png 图像,这比我管理的要多,所以应该可以!非常感谢!!

以上是关于Google Apps 脚本文件上传(通过 HTML 表单)仅在脚本“绑定”时有效(测试独立脚本时,HTTP 403 错误)的主要内容,如果未能解决你的问题,请参考以下文章

无法通过 Google Apps 脚本中的 YouTube 数据 API 从云端硬盘上传:空响应

将 Google Apps 脚本中的 CSV 文件上传到 BigQuery 表 - 行中的恶意逗号

使用 HtmlService 使用 Google Apps 脚本上传文件

如何在对 Google Apps 脚本的发布请求中捕获上传的文件?

使用 Google Apps 脚本将文件上传到我的 google 驱动器(在 GOOGLE 中没有表格)

Wordpress 说,“rest_upload_sideload_error”表示从 Google Apps 脚本上传的图像中的可识别类型。为啥?