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

Posted

技术标签:

【中文标题】使用 Google Apps 脚本将文件上传到我的 google 驱动器(在 GOOGLE 中没有表格)【英文标题】:Upload file to my google drive with Google Apps Script (NO FORM IN GOOGLE) 【发布时间】:2020-12-02 02:24:17 【问题描述】:

所以基本上任务很简单,但我没有找到任何可行的解决方案来解决我的问题。我的网站上有一个巨大的上传脚本(目前是 localhost),但让我们将所有复杂性降低到唯一必要的程度。

所以我只想使用 Google App Script 将单个文件上传到 Google Drive,并接收它的 URL 以将其保存在 var 中,以便稍后在我的函数中使用该信息。强>

现在的问题是我的网站上已经有表单,我不希望 script.google.com 中的表单作为额外的 html,我想将我的用户输入传输到 Google App Script,然后将其上传到谷歌驱动器和将 url 返回到我的网站,我可以将其保存到 var 中。

我现在的问题是,我不能把所有的东西放在一起。

这是我网站上的表格(简化版):

<form name="myForm" method="post">
            <!-- <form name="first-form"> -->

  <input type="text" placeholder="Name" id="myName">
  <input type="file" name="myFile" id="myFile">
  <button onclick="UploadFile()" type="submit">submit</button>

</form>

那么我怎样才能在 google drive 中上传我的信息并取回结果呢?如何在不使用 iFrame 或其他任何东西的情况下在 Google App Script 中推送数据?

谢谢!

**** html 在 scripts.google.com 中的工作示例 ****

gs

function doGet(e) 
  return HtmlService.createHtmlOutputFromFile('forms.html').setTitle("Google File Upload by CTRLQ.org");



function uploadFileToGoogleDrive(data, file, name, email) 
  
  try 
    
    var dropbox = "Received Files";
    var folder, folders = DriveApp.getFoldersByName(dropbox);
    
    if (folders.hasNext()) 
      folder = folders.next();
     else 
      folder = DriveApp.createFolder(dropbox);
    
    
    /* Credit: www.labnol.org/awesome */
    
    var contentType = data.substring(5,data.indexOf(';')),
        bytes = Utilities.base64Decode(data.substr(data.indexOf('base64,')+7)),
        blob = Utilities.newBlob(bytes, contentType, file),
        file = folder.createFolder([name, email].join(" ")).createFile(blob);
    
    return "OK";
    
   catch (f) 
    return f.toString();
  
  

apps.googlescript 中的html

<!DOCTYPE html>
<html>
  <head>
    <base target="_blank">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Google File Upload by CTRLQ.org</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
    <style>
      .disclaimerwidth: 480px; color:#646464;margin:20px auto;padding:0 16px;text-align:center;font:400 12px Roboto,Helvetica,Arial,sans-serif.disclaimer acolor:#009688#creditdisplay:none
    </style>
  </head>
  <body>

    <!-- Written by Amit Agarwal amit@labnol.org --> 

    <form class="main" id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;">
      <div id="forminner">
        <div class="row">
          <div class="col s12">
            <h5 class="center-align teal-text">Upload Files to my Google Drive</h5>
            <p class="disclaimer">This <a href="http://www.labnol.org/internet/file-upload-google-forms/29170/">File Upload Form</a> (<a href="https://youtu.be/C_YBBupebvE">tutorial</a>) is powered by <a href="https://ctrlq.org/code/19747-google-forms-upload-files" target="_blank">Google Scripts</a></p>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12">
            <input id="name" type="text" name="Name" class="validate" required="" aria-required="true">
            <label for="name">Name</label>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12">
            <input id="email" type="email" name="Email" class="validate" required="" aria-required="true">
            <label for="email">Email Address</label>
          </div>
        </div>

        <div class="row">
          <div class="file-field input-field col s12">
            <div class="btn">
              <span>File</span>
              <input id="files" type="file">
            </div>
            <div class="file-path-wrapper">
              <input class="file-path validate" type="text" placeholder="Select a file on your computer">
            </div>
          </div>
        </div>

        <div class="row">
          <div class="input-field col s6">
            <button class="waves-effect waves-light btn submit-btn" type="submit" onclick="submitForm(); return false;">Submit</button>
          </div>   
        </div>
        <div class="row">
          <div class="input-field col s12" id = "progress">
          </div>
        </div>
      </div>
      <div id="success" style="display:none">
        <h5 class="left-align teal-text">File Uploaded</h5>
        <p>Your file has been successfully uploaded.</p>
        <p>The <a href="http://www.labnol.org/internet/file-upload-google-forms/29170/">pro version</a> (see <a href="">demo form</a>) includes a visual drag-n-drop form builder, CAPTCHAs, the form responses are saved in a Google Spreadsheet and respondents can upload multiple files of any size.</p>    
        <p class="center-align"><a  class="btn btn-large" href="https://gum.co/GA14?wanted=true" target="_blank">Upgrade to Pro</a></p>
      </div>
    </form>

    <div class="fixed-action-btn horizontal" style="bottom: 45px; right: 24px;">
      <a class="btn-floating btn-large red">
        <i class="large material-icons">menu</i>
      </a>
      <ul>
        <li><a class="btn-floating red"  href="https://gum.co/GA14" target="_blank" title="Buy License - File Upload Form"><i class="material-icons">monetization_on</i></a></li>
        <li><a class="btn-floating blue"  href="https://youtu.be/C_YBBupebvE" target="_blank" title="Video Tutorial"><i class="material-icons">video_library</i></a></li>
        <li><a class="btn-floating green" href="http://www.labnol.org/internet/file-upload-google-forms/29170/" target="_blank" title="How to Create File Upload Forms"><i class="material-icons">help</i></a></li>
      </ul>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
    <script src="https://gumroad.com/js/gumroad.js"></script>

    <script>

      var file, 
          reader = new FileReader();

      reader.onloadend = function(e) 
        if (e.target.error != null) 
          showError("File " + file.name + " could not be read.");
          return;
         else 
          google.script.run
            .withSuccessHandler(showSuccess)
            .uploadFileToGoogleDrive(e.target.result, file.name, $('input#name').val(), $('input#email').val());
        
      ;

      function showSuccess(e) 
        if (e === "OK")  
          $('#forminner').hide();
          $('#success').show();
         else 
          showError(e);
        
      

      function submitForm() 

        var files = $('#files')[0].files;

        if (files.length === 0) 
          showError("Please select a file to upload");
          return;
        

        file = files[0];

        if (file.size > 1024 * 1024 * 5) 
          showError("The file size should be < 5 MB. Please <a href='http://www.labnol.org/internet/file-upload-google-forms/29170/' target='_blank'>upgrade to premium</a> for receiving larger files in Google Drive");
          return;
        

        showMessage("Uploading file..");

        reader.readAsDataURL(file);

      

      function showError(e) 
        $('#progress').addClass('red-text').html(e);
      

      function showMessage(e) 
        $('#progress').removeClass('red-text').html(e);
      


    </script>

  </body>

</html>

建议我在这里描述这个过程。

所以我们在网站上:www.example.com,有一个带有文本输入字段和文件字段的表单。假设我们放入一个图像并将其称为示例。现在,如果我们按下提交,我想在没有任何 oAuth 的情况下将图像上传到谷歌驱动器(这就是我们需要在这里使用谷歌应用脚​​本的原因)并将其命名为我们在文本字段中键入的内容。上传完成后,我希望将谷歌驱动器图像的 url 返回到网站,以便表单可以继续使用该信息。然后我想将返回的 url 保存在一个 var 中,以便稍后将其保存在数据库中。这就是为什么我需要将结果返回到我的网站。

所以方案如下所示:

在网站上输入信息以形成 -> 重定向到谷歌应用脚​​本:获取网站表单字段的信息并将文件上传到谷歌驱动器并将其命名为文本输入条目 -> 将谷歌驱动器的 URL 作为最终结果 -> 重定向最终url 结果返回到网站 -> 将 url 结果保存在 var 中并继续从网站上的函数执行操作 -> 最后将信息从 var 保存到数据库 -> 完成

----------------------------------- - 编辑:------------------

感谢@Tanaike,我离我的挑战目标更近了,所以为了看看我卡在哪里,我现在正在复制我的问题:

我使用您示例中的脚本获取表单:

<form id="form">
  <input name="file" id="uploadfile" type="file">
  <input name="filename" id="filename" type="text">
  <input id="submit" type="submit">
</form>
<script>
const form = document.getElementById('form');
form.addEventListener('submit', e => 
  e.preventDefault();
  const file = form.file.files[0];
  const fr = new FileReader();
  fr.readAsArrayBuffer(file);
  fr.onload = f => 
    
    const url = "https://script.google.com/macros/s/###/exec";  // <--- Please set the URL of Web Apps.
    
    const qs = new URLSearchParams(filename: form.filename.value || file.name, mimeType: file.type);
    fetch(`$url?$qs`, method: "POST", body: JSON.stringify([...new Int8Array(f.target.result)]))
    .then(res => res.json())
    .then(e => console.log(e))  // <--- You can retrieve the returned value here.
    .catch(err => console.log(err));
  
);
</script>

对于谷歌脚本:

function doPost(e) 
  // const folderId = "###";  // Folder ID which is used for putting the file, if you need.

  const blob = Utilities.newBlob(JSON.parse(e.postData.contents), e.parameter.mimeType, e.parameter.filename);
  const file = DriveApp.getFolderById(folderId || "root").createFile(blob);
  const responseObj = filename: file.getName(), fileId: file.getId(), fileUrl: file.getUrl();
  return ContentService.createTextOutput(JSON.stringify(responseObj)).setMimeType(ContentService.MimeType.JSON);

现在,当我尝试上传内容时,出现以下错误:CORS 策略无法获取。所以我把这部分改成以下,并添加了mode no cors:

const qs = new URLSearchParams(filename: form.filename.value || file.name, mimeType: file.type);
        fetch(`$url?$qs`, method: "POST", mode: "no-cors", body: JSON.stringify([...new Int8Array(f.target.result)]))

这行得通。第二次尝试上传文件导致出现以下错误: 它说:syntax error: unexpected end of input

所以我更改了这一行并从 res.json 中删除了括号

JSON.stringify([...new Int8Array(f.target.result)]))
        .then(res => res.json)

第三次尝试上传文件实际使用了以下控制台结果:

ƒ json()  [native code] 

但谷歌驱动器中没有上传文件。我在某处遗漏了一些东西。也许我们应该创建一个文件夹并将文件放在那里。

哦,还有另一个信息:当我在 google app sript 中运行 doPost 功能时,它说:

TypeError: Cannot read property 'postData' of undefined (line 13

EDIT2 -----------------------------------------

我在您的代码中添加了https://drive.google.com/uc?export=download&id=###fileId###,一切正常。文件正在上传。

假设我们上传了文件 test.mp3,我们称之为 testdata。 这是我们收到的:


  "filename": "testdata",
  "fileId": "###some id##",
  "fileUrl": "https://drive.google.com/uc?export=download&id=###fileId###"

现在,当我打开文件 url 时,浏览器会下载文件,但它的名称是:testdata,而不是 testdata.mp3。缺少文件类型结尾。

第二个任务:如果你点击链接,我想在浏览器中打开文件,例如它的 mp3 文件我希望你可以在 webview 中播放声音,就像在这里:https://files.freemusicarchive.org/storage-freemusicarchive-org/music/Creative_Commons/Dead_Combo/CC_Affiliates_Mixtape_1/Dead_Combo_-_01_-_Povo_Que_Cas_Descalo.mp3

希望你能指导我!

【问题讨论】:

查看:developers.google.com/picker/docs 感谢您提供的链接,据我所知,您需要 oAuth 身份验证,我需要公开上传,所以这种方法对我不起作用。 试用一个.web 应用程序,我将它构建到您的网站中 这会是什么样子?我需要一个结果到我的网站,然后将其保存在 var 中,是否可以使用 iframe? 这有点难以理解。你能列出工作流程的分步流程吗? Submit form &gt; data gets posted to x &gt; redirect to y 等? 【参考方案1】:

https://***.com/a/63391363/1585523 回答中有很多有用的提示!谢谢你的分享。除了 POST 文件,我们还可以使用

在客户端:index.html

google.script.run.withSuccessHandler(fileName => ).withFailureHandler(error => ).saveInDrive(fileAsByteArray);

在服务器上:Code.gs

function saveInDrive(f) 
  const blob = Utilities.newBlob(f, "image/jpeg", "some-name");
  const file = DriveApp.getFolderById("root").createFile(blob);
  return file.getName()

在这种方法中,您甚至可以使用二进制信息作为值来交换 JS 对象等复杂类型。

【讨论】:

能否详细说明 fileAsByteArray 是如何定义的? 取决于您获取原始文件的方式。源上可以获取 API:例如const fileAsByteArray = new File([Uint8Array.from(await fetchResp)], "myfile.bin")。 developer.mozilla.org/en-US/docs/Web/javascript/Reference/… 以多种方式参与进来【参考方案2】:

我相信你的目标如下。

您的网站与 Google 帐户无关。它是独立的。 您的网站有一个用于上传文件的表单。 当用户提交表单时,您想在未经授权的情况下将文件上传到您的 Google Drive,并希望返回已上传文件在 Google Drive 上的 URL。 关于“数据库”,这是您的数据库。您将检索到的文件的 URL 放到客户端的“数据库”中。

在这种情况下,我认为您的目标可以使用 Google Apps Script 创建的 Web Apps 来实现。

用法:

请执行以下流程。

1。创建 Google Apps 脚本的新项目。

Web Apps 的示例脚本是 Google Apps 脚本。所以请创建一个 Google Apps Script 项目。

如果要直接创建,请访问https://script.new/。在这种情况下,如果您没有登录 Google,则会打开登录屏幕。所以请登录谷歌。这样,Google Apps Script 的脚本编辑器就打开了。

2。准备脚本。

请将以下脚本(Google Apps 脚本)复制并粘贴到脚本编辑器中。此脚本适用于 Web 应用程序。

服务器端:Google Apps 脚本

请设置您要放置文件的文件夹ID。

function doPost(e) 
  const folderId = "root";  // Or Folder ID which is used for putting the file instead of "root", if you need.

  const blob = Utilities.newBlob(JSON.parse(e.postData.contents), e.parameter.mimeType, e.parameter.filename);
  const file = DriveApp.getFolderById(folderId).createFile(blob);
  const responseObj = filename: file.getName(), fileId: file.getId(), fileUrl: file.getUrl();
  return ContentService.createTextOutput(JSON.stringify(responseObj)).setMimeType(ContentService.MimeType.JSON);

3。部署 Web 应用程序。

    在脚本编辑器上,通过“发布”->“部署为 Web 应用”打开一个对话框。 为“执行应用程序为:”选择“我”。 由此,脚本以所有者身份运行。 为“谁有权访问应用程序:”选择“任何人,甚至是匿名的”。 单击“部署”按钮作为新的“项目版本”。 自动打开“需要授权”对话框。
      点击“查看权限”。 选择自己的帐户。 点击“此应用未验证”中的“高级”。 点击“转到###项目名称###(不安全)” 点击“允许”按钮。
    点击“确定”。 复制 Web 应用程序的 URL。就像https://script.google.com/macros/s/###/exec当您修改 Google Apps 脚本时,请重新部署为新版本。这样,修改后的脚本就会反映到 Web 应用程序中。请注意这一点。

4。将文件从客户端上传到服务器端。

客户端:HTML & Javascript

请将您的 Web 应用的 URL 设置为以下脚本。

<form id="form">
  <input name="file" id="uploadfile" type="file">
  <input name="filename" id="filename" type="text">
  <input id="submit" type="submit">
</form>
<script>
const form = document.getElementById('form');
form.addEventListener('submit', e => 
  e.preventDefault();
  const file = form.file.files[0];
  const fr = new FileReader();
  fr.readAsArrayBuffer(file);
  fr.onload = f => 
    
    const url = "https://script.google.com/macros/s/###/exec";  // <--- Please set the URL of Web Apps.
    
    const qs = new URLSearchParams(filename: form.filename.value || file.name, mimeType: file.type);
    fetch(`$url?$qs`, method: "POST", body: JSON.stringify([...new Int8Array(f.target.result)]))
    .then(res => res.json())
    .then(e => console.log(e))  // <--- You can retrieve the returned value here.
    .catch(err => console.log(err));
  
);
</script>
在客户端,当您从本地 PC 中选择一个文件并按下按钮时,该文件会通过在 Web 应用程序(服务器端)检索数据而上传到您的 Google 云端硬盘。 结果:

运行上述脚本时,将返回以下值。从中,您可以检索文件的 URL。


  "filename": "### inputted filename ###",
  "fileId": "###",
  "fileUrl": "https://drive.google.com/file/d/###/view?usp=drivesdk"

注意:

当您修改 Web Apps 的脚本时,请将 Web Apps 重新部署为新版本。这样,最新的脚本就会反映到 Web 应用程序中。请注意这一点。 在上述脚本中,最大文件大小为 50 MB。因为在当前阶段,Google Apps 脚本的最大 Blob 大小为 50 MB。

参考资料:

Web Apps Taking advantage of Web Apps with Google Apps Script

【讨论】:

这太棒了!!千感谢这个信息丰富的分步指南!当我完成工作时我会尝试它,但是我通过快速滚动看到的,有很多你提供给我的相关信息,这似乎是我挑战的完美解决方案。我只能再说一遍,非常感谢你!! 早上好,我想让你给你一些反馈。所以首先我得到了 cors 策略错误,但我通过在 fetch post 后添加 mode: 'no-cors' 到该行来解决这个问题。现在我在这一行得到一个语法错误:.then(res => res.json()),它说输入意外结束 @Marcel Dz 感谢您的回复。我带来的不便表示歉意。不幸的是,我无法复制您的情况。因为当我测试它时,我可以确认没有错误发生。所以我在上面提出了它。我对此深表歉意。为了正确了解您的情况并正确复制您的情况,您能否提供复制当前问题的详细信息?借此,我想确认一下。如果您能合作解决您的问题,我很高兴。你能合作解决你的问题吗?如果可以,请在您的问题中添加详细流程。 感谢您的快速回复,我只是通过将 .then(res => res.json() 更改为 .then( res=> res.json) 而不使用括号来获得它。现在当我上传了一个文件,我收到这样的内容:ƒ json() [native code] 但文件尚未上传到驱动器中 @Marcel Dz 感谢您的回复。我带来的不便表示歉意。不幸的是,我无法复制您的情况。因为当我测试它时,我可以确认没有错误发生。所以我在上面提出了它。我对此深表歉意。为了正确了解您的情况并正确复制您的情况,您能否提供复制当前问题的详细信息?借此,我想确认一下。如果您能合作解决您的问题,我很高兴。你能合作解决你的问题吗?如果可以,请在您的问题中添加详细流程。

以上是关于使用 Google Apps 脚本将文件上传到我的 google 驱动器(在 GOOGLE 中没有表格)的主要内容,如果未能解决你的问题,请参考以下文章

Google Forms文件上传完整示例

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

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

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

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

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