【问题标题】:How to pass file upload blob from HTML form to server-side Apps Script?如何将文件上传 blob 从 HTML 表单传递到服务器端 Apps 脚本?
【发布时间】:2019-08-20 15:57:40
【问题描述】:

表单标题下的 Google support article 示例已损坏。来自文章:

如果您以表单元素作为参数调用服务器函数,则表单将成为单个对象,其中字段名称作为键,字段值作为值。这些值都被转换为字符串,除了文件输入字段的内容,它们变成了 Blob 对象。

我通过传递一个包含 5 个文本输入和一个文件的表单元素来测试这一点,然后在表单对象上记录 Object.keys()。它仅返回 5 个文本字段,该文件已从表单对象中剥离。尝试分配文件 blob 直接返回Exception: Invalid argument: blob

如何将文件 blob 从客户端表单传递到服务器端 Apps 脚本?

编辑:为了澄清,我还逐字复制粘贴了 Google 提供的示例。它与Exception: Invalid argument: blob 出错。

复制:

  1. 创建新的 Google Apps 脚本项目
  2. Index.html 内容:
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      // Prevent forms from submitting.
      function preventFormSubmit() {
        var forms = document.querySelectorAll('form');
        for (var i = 0; i < forms.length; i++) {
          forms[i].addEventListener('submit', function(event) {
            event.preventDefault();
          });
        }
      }
      window.addEventListener('load', preventFormSubmit);

      function handleFormSubmit(formObject) {
        google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
      }
      function updateUrl(url) {
        var div = document.getElementById('output');
        div.innerHTML = '<a href="' + url + '">Got it!</a>';
      }
    </script>
  </head>
  <body>
    <form id="myForm" onsubmit="handleFormSubmit(this)">
      <input name="myFile" type="file" />
      <input type="submit" value="Submit" />
    </form>
    <div id="output"></div>
 </body>
</html>
  1. Code.gs 内容:
function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function processForm(formObject) {
  var formBlob = formObject.myFile;
  var driveFile = DriveApp.createFile(formBlob);
  return driveFile.getUrl();
}
  1. 作为网络应用发布
  2. 使用任何文件提交表单
  3. 在视图中观察错误 -> Stackdriver 日志记录 -> Apps 脚本仪表板

【问题讨论】:

  • 如文档所述,您应该发送表单element 而不是表单object
  • 我用错了词...我更新了问题。我通过了 HTML 表单元素。
  • 展示你是如何用代码传递元素的。提供minimal reproducible example。这是Exception: Invalid argument: blob. 客户端还是服务器端?
  • 您的代码在我上传 .pdf 文件的测试中完美运行。您上传的文件的 MIME 类型是什么?
  • @AndresDuarte 我尝试了各种(txt、xlsx、png),没有任何效果。听到完全相同的代码适用于其他人现在让我相信我的公司存在某种公司限制。 (◔_◔)

标签: google-apps-script


【解决方案1】:

这是一个例子:

html:

<!DOCTYPE html>
<html>
  <head>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <script>
  function fileUploadJs(frmData) {
    document.getElementById('status').style.display ='inline';
    google.script.run
      .withSuccessHandler(updateOutput)
      .uploadTheFile(frmData)
  }

  function updateOutput(info)  {
    var br='<br />';
    var outputDiv = document.getElementById('status');
    outputDiv.innerHTML = br + 'File Upload Successful.' + br + 'File Name: ' + info.name + br + 'Content Type: ' + info.type + br + 'Folder Name: ' + info.folder;
  }

  console.log('My Code');
</script>
<style>
  body {background-color:#ffffff;}
  input{padding:2px;margin:2px;}
</style>

  </head>
  <body>
    <h1 id="main-heading">Walking Tracks</h1>
    <h3>Upload GPS Tracks Files</h3>
    <div id="formDiv">
      <form id="myForm">
        <input name="fileToLoad" type="file" /><br/>
        <input type="button" value="Submit" onclick="fileUploadJs(this.parentNode)" />
      </form>
    </div>
  <div id="status" style="display: none">
  <!-- div will be filled with innerHTML after form submission. -->
  Uploading. Please wait...
  </div>  
  <div id="controls">
      <input type="button" value="Close" onClick="google.script.host.close();" />
  </div>
</body>
</html>

服务器代码:

function uploadTheFile(theForm) {
  var fileBlob=theForm.fileToLoad;
  var fldr = DriveApp.getFolderById('FolderId');
  var file=fldr.createFile(fileBlob);
  var fi=formatFileName(file);
  var fileInfo={'name':fi.getName(),'type':fileBlob.getContentType(), 'size':fileBlob.getBytes(), 'folder':fldr.getName()};
  return fileInfo;
}

【讨论】:

  • 我更新了您的 getFolderById 方法以检索我的驱动器中存在的内容,但它仍然对我不起作用。同样的问题,fileBlob 为空...theForm 不包含 fileToLoad 的键。我现在想知道这是否是我组织的公司安全策略……或者我们与 Google 的协议以某种方式限制了某些功能?相同的代码适用于其他人,但不适用于我的组织。没有意义。
  • 这是一个工作函数。我几乎每天都用它从 DropBox 上传 GPS 轨迹文件
【解决方案2】:

我可以确认这在 G-Suite Enterprise 中不起作用。我不知道为什么,因为我找不到说明 Google 如何序列化数据的文档。它可能是浏览器/计算机安全设置或 G-Suite 中的其他设置。

但是,有一种更简单的方法可以满足您的需求。您可以使用带有文件上传问题的 Google 表单,然后在其上创建 on form submit 触发器/事件以将文件复制到团队/共享驱动器。如果您想将触发器附加到 Google 表单本身,这里是示例代码:

// ID of the destnation folder to save the file in
var destinationFolderID = "10gkU_2V9iYy-VKudOCOjydEpoepPTgPv"

function saveFileToTeamDrive(e)
{
  // a place to save the URL of the uploaded file
  var fileID;

  // go through all of the responses to find the URL of the uploaded file
  e.response.getItemResponses().forEach(function(itemResponse){
    // once we find the question with the file
    if(itemResponse.getItem().getTitle() == "File Upload Test")
    {
      // get the file ID from the response
      fileID = itemResponse.getResponse();
      return;
    }
  });

  // stop if we didn't have one
  if(!fileID.length) return;

  // get the first index in the array
  fileID = fileID[0];

  // get the file
  var file = DriveApp.getFileById(fileID);

  // get the destination folder
  var destinationFolder = DriveApp.getFolderById(destinationFolderID);

  // make a copy
  var newFile = file.makeCopy(destinationFolder);

  Logger.log(newFile.getUrl());
}

您还可以附加到链接到 Google 表单的 Google 表格的 on form submit 事件。我发现这种方式更容易,因为 Google Sheet on form submit trigger/event 包含问题/答案的 JSON,因此您不必遍历所有这些来找到它。这也意味着如果提交失败,您可以重新运行提交。

警告

重要的一点是,如果您执行上述任何一项操作,请不要授予其他任何人对代码的编辑权限。这是因为一旦您创建并授权触发器,任何对代码具有编辑权限的人都可以使用它来访问您的 Google Drive(以及触发器被授权的任何其他内容)。请参阅securing a Google Apps Script linked to an authorized trigger so others can edit 了解更多信息。

【讨论】:

    猜你喜欢
    • 2021-08-08
    • 1970-01-01
    • 2023-04-11
    • 2016-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 2015-09-01
    相关资源
    最近更新 更多