运行从Google网站发布在Webapp中的功能 [英] Run a function published in Webapp from a Google site

查看:55
本文介绍了运行从Google网站发布在Webapp中的功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从Google网站的web应用程序中运行一个功能,作为 onload 函数。

I want to run a function in a webapp from a google site as onload function.

code.gs

function doGet(e){
  return HtmlService.createHtmlOutputFromFile("page"); 
}

function myfunc(datavalues) {
      var sheetURL = 'https://docs.google.com/spreadsheets/d/SHEET-ID-IS-HERE';
     // Current Active Sheet
     var activeGoogleSheet = SpreadsheetApp.openByUrl(sheetURL);
     var activeSheet = activeGoogleSheet.getActiveSheet();
      activeSheet.getRange(1,1).setValue(datavalues[0]);
      activeSheet.getRange(1,2).setValue(datavalues[1]);
     // ---------------------------------------------------- //
}

page.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
  
    <body>
  </body>
  
  
  <script>
       // function run from code.gs
       function runfunc(values){
                 google.script.run.myfunc(values);
       }
       
  </script>
</html>

最后,我在Google网站中嵌入了以下代码:

Finally, i have following code embeded in google site :

<!DOCTYPE html>
<html>
<script src="https://script.google.com/a/macros/s/WEBAPPURL/exec"></script>
<script>
    function loadFunc(){
         var values = ['aaaa',123];
         runfunc(values);       
 }
</script>


<body onload='loadFunc()'>

<body/>
</html>

这应该将值写入Google工作表,但无法正常工作。甚至可以从webapp运行这样的功能吗?是运行某些东西还是有其他选择?

This should write the values to the google sheet, but it is not working. Is it even possible to run function like this from webapp? Is something run or is there an alternative?

问题的更新:
code.gs doPost

code.gs

    function doGet(e){
     console.log("get request");
      return HtmlService.createHtmlOutputFromFile("page"); 
    }
    
    function myfunc(datavalues) {
          var sheetURL = 'https://docs.google.com/spreadsheets/d/SHEET-ID-IS-HERE';
         // Current Active Sheet
         var activeGoogleSheet = SpreadsheetApp.openByUrl(sheetURL);
         var activeSheet = activeGoogleSheet.getActiveSheet();
          activeSheet.getRange(1,1).setValue(datavalues[0]);
          activeSheet.getRange(1,2).setValue(datavalues[1]);
         // ---------------------------------------------------- //
    }
// Post method
function doPost(datavalues){
  console.log("post Request");
// check the parameters


 if(typeof e !== 'undefined')
  var datavalues =  JSON.stringify(JSON.parse(e.parameter)); 
  console.log(datavalues);
  var sheetURL = 'https://docs.google.com/spreadsheets/d/URL/';
     // Current Active Sheet
     var activeGoogleSheet = SpreadsheetApp.openByUrl(sheetURL);
     var activeSheet = activeGoogleSheet.getActiveSheet();
     // first empty row
     var dataRow = activeSheet.getDataRange().getLastRow()+1;
     // ---------------------------------------------------- //
     // writing data to the sheet
     // ---------------------------------------------------- //
          activeSheet.getRange(dataRow,1).setValue(datavalues['a']);
         activeSheet.getRange(dataRow,2).setValue(datavalues['b']);
     // ---------------------------------------------------- // 
   return ContentService.createTextOutput(JSON.stringify(e));
    }

嵌入Google网站的代码:

Code embedded in google site :

<!DOCTYPE html>
<html>
<script>
function postRequest(url, data) {
  return fetch(url, {
    method: 'POST', 
    credentials: 'omit';
    headers: {'Accept': 'application/json',
    'Content-Type': 'application/json'
    }
    body:  JSON.stringify(data);
 });
}

function onloadfunc(){
console.log('loadding');
var data = {'a':'xxx','b':'ppp'};
postRequest('https://script.google.com/a/macros/s/WEBAPP/exec', data).then(function(response) {
    console.log("ok");
}).catch(function(error) {
    console.log(error);
}
</script>


<body onload="onloadfunc()">
<body/>


</html>

同时更新到 doPost 和后请求功能。但仍然无法正常工作。

Update to both doPost and the function to postrequest. but still does not work.

控制台中的错误:


加载资源失败:服务器响应状态为405()
可从
'https://script.google.com/a/macros/s/WEBAPPURL/exec'获取
的来源(https://2008039421-atari-embeds.googleusercontent.com '
已被CORS政策阻止:对预检请求的响应未通过
通过访问控制检查:所请求的资源上没有
'Access-Control-Allow-Origin'标头。如果不透明的响应满足您的
需求,请设置要求est的模式设置为 no-cors以在禁用
CORS的情况下获取资源。

Failed to load resource: the server responded with a status of 405 () Access to fetch at 'https://script.google.com/a/macros/s/WEBAPPURL/exec' from origin 'https://2008039421-atari-embeds.googleusercontent.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.




我添加了 mode: no-cors fetch 并运行 onloadfunc()现在并运行提取。它给我有关 fetch 或函数的其他错误,但现在却给了我以下错误。


I added mode:'no-cors' to the fetch and that runs the onloadfunc() now and runs the fetch. It gives me other error regarding the fetch or the function but now it gives me the following error.


无法加载资源:服务器的响应状态为401()

Failed to load resource: the server responded with a status of 401 ()

该网络应用可供网络和Google网站中的任何人使用也正在通过网络使用它。因此,身份验证应该没有问题。我不知道现在出了什么问题。

The webapp is open to use for anyone in the network and the google site is also using it through the network. So it should not have problem with authentication. I do not know what is wrong now.

带有 JSON.stringify

Latest error with JSON.stringify

<!DOCTYPE html>
<html>
<script>
function postRequest(url, data) {
  return fetch(url, {
    method: 'POST', 
    mode: 'no-cors',
    headers: {
    'Accept': 'application/x-www-form-urlencoded',
    'Content-Type': 'application/x-www-form-urlencoded'
    },
    credentials:'include',
    body: data
  });
}
function onloadfunc(){
console.log('loading');
var data = JSON.stringify({'a':'xxx','b':'ppp'});
 postRequest('https://script.google.com/a/WEBAPP/exec', data).then(function(response) {
 var div = document.getElementById('errorOutput');
      div.innerHTML = "response"+response;
        console.log("ok");
    }).catch(function(error) {
     var div = document.getElementById('errorOutput');
      div.innerHTML = "error"+error;
    console.log(error);});
}
</script>
<body onload="onloadfunc()">
<div id="errorOutput"></div>
</body>
</html>

code.gs

// Post method
function doPost(e){
  //console.log(JSON.stringify(e,null, 2));
  // check the parameters
  if(typeof e !== 'undefined')
  console.log(e);
  var datavalues = e.parameter; 
  var sheetURL = 'https://docs.google.com/spreadsheets/d/SHEETURL/';
     // Current Active Sheet
     var activeGoogleSheet = SpreadsheetApp.openByUrl(sheetURL);
     var activeSheet = activeGoogleSheet.getActiveSheet();
     // first empty row
     var dataRow = activeSheet.getDataRange().getLastRow()+1;
     // ---------------------------------------------------- //
     // writing data to the sheet
     // ---------------------------------------------------- //

          activeSheet.getRange(dataRow,1).setValue(datavalues.a);
     
         activeSheet.getRange(dataRow,2).setValue(datavalues.b);
     // ---------------------------------------------------- // 
   return ContentService.createTextOutput(JSON.stringify(e));
}

这样,称为 doPost 它有效!!!
现在唯一的问题是我的字典传递错误。
在站点中为 {'a':'xxx','b':'ppp'} ,但传递的总参数看起来像(结果 console.log(e)):

With this, the doPost is called and it works!!! Only problem now i have is my dictionary is passed wrong. In site it is {'a':'xxx','b':'ppp'} but the total argument passed looks like (result of console.log(e)) :

{parameter={{"a":"xxx","b":"ppp"}=}, contextPath=, contentLength=31, queryString=, parameters={{"a":"xxx","b":"ppp"}=[]}, postData=FileUpload}

莫名其妙地 = ,然后按原样传递字典。

Somehow extra = is added and then the dictionary is passed as it is.

推荐答案

目标:



  • 使用带有

    • 访问权限的域中的任何人使用Google Apps脚本在域中发布的WebApp中运行特定功能


      • 在相同域中发布的新Google网站。


      • CORS: Google应用程序脚本Web应用程序(以下称为Gas-webapp)和Google网站中的用户代码(她的之后,Gs webapp)就可以在不同来源的iframe中运行- https:// [DIFFERENT_URL] .googleusercontent.com 沙盒放在 * google.com

      • CORS: Both the Google apps script web app(hereafter, Gas-webapp) and user code in Google sites(hereafter, Gs webapp) run in iframes of different origin- https://[DIFFERENT_URL].googleusercontent.com sandboxed in *google.com.

      • 使用获取 api从Google网站到Web应用程序 POST 数据。

      • 接收<$来自Google网站的c $ c> POST 请求并执行该功能。

      • Use Fetch api to POST data from Google sites to web-app.
      • Receive POST request from Google sites and execute the function.
      • CORS
      • Fetch API Spec

      • Gas网络应用默认提供以下功能任何经过身份验证的CORS请求的CORS响应标头:

      • Gas web-app by default provides the following CORS response header to any authenticated CORS request:


      • Access-Control-Allow-Origin:*

      • Access-Control-Allow-Origin : *

      但是,如果请求未经身份验证,或者脚本错误,您将被重定向到Google的登录页面/错误页面;这两个页面都没有设置 Access-Control-Allow-Origin ,访问将被阻止从所有网页。

      However, If the requested is unauthenticated or if the script errors out, You're redirected to Google's login page/error page; Both pages doesn't have Access-Control-Allow-Origin set and access will be blocked from all web pages.

      上面提到的未经身份验证的请求的唯一例外是发布具有访问权限的Gas Web应用:任何人, 甚至是匿名

      The only exception to the unauthenticated requests mentioned above is publishing Gas web-app with access: Anyone,even anonymous.

      Gas Web App不允许 OPTIONS 方法。因此,所有已准备就绪的请求都会失败。

      Gas web-app doesn't allow OPTIONS method. Hence, all requests that are preflighted will fail.

      与gas-web应用程序兼容的唯一剩余CORS选项是 简单请求 ,它们没有被浏览器预检。

      The only remaining CORS option compatible with gas-web app is Simple requests, that are not preflighted by the browser.

      但是,简单的 POST 请求基本上未经身份验证。在此脚本中,我们使用 凭据选项在请求中,以包含第三方凭据。在这里,我们使用的是用户帐户的Google凭据。通过使用此选项,我们实际上是在使用用户帐户的Google凭据进行身份验证。使用此选项必须满足以下条件:

      However, simple POST requests are essentially unauthenticated. In this script, We use the credentials option in the request to include third party credentials. Here, we are after User account's Google's credentials. By using this option, We are essentially authenticating using user account's Google's credentials. The following conditions must be satisfied to use this option:


      • 用户必须登录到Google,以便具有登录Cookie来与发布请求一起发送

      • 由于iframe的来源不同,因此必须在浏览器中启用第三方Cookie。

      请求模式可以设置为 cors no-cors

      但是,如果根据cors -credentials rel = nofollow noreferrer>规范文档,必须由gas网络应用提供以下响应标头才能发布具有凭据的请求:

      However, If cors is set, according to the spec documentation, the following response header must be provided by the gas web-app to post request with credentials:

      访问控制-Allow-Credentials

      Access-Control-Allow-Credentials

      gas-webapp不提供此功能。尽管请求将被发送(因为它没有预检),但无法接收(不共享)响应,即 doPost 仍将运行,但是响应不能被执行

      This is not provided by the gas-webapp. Though the request will be send(as it is not preflighted), the response can't be received(not shared), i.e., doPost will still run, but response cannot be received by the gs-webapp.

      • If no-cors is set, fetch will return an "opaque filtered response"(a empty response).


      不透明的已过滤响应是类型为不透明的已过滤响应,URL列表为空列表,状态为0。 ,状态消息为空字节序列,标头列表为空,主体为null,尾部为空。

      An opaque filtered response is a filtered response whose type is "opaque", URL list is the empty list, status is 0, status message is the empty byte sequence, header list is empty, body is null, and trailer is empty.



    • 本质上,当访问权限设置为任何人(非匿名)时,您可以从gs-web-app到gas-web-app进行单向通信。

    • In essence, You can do a one way communication from gs-web-app to gas-web-app, when access is set to Anyone(not anonymous).

      POST 使用 application / x-www进行的请求-form-urlencoded 必须为以下格式的字符串: input1 = 1& input2 = 4 URLSearchParams 可用于从对象中制作这样的字符串。

      POST requests made with application/x-www-form-urlencoded must be a string of format: input1=1&input2=4. URLSearchParams could be used to craft such string from objects.

          <!DOCTYPE html>
          <html>
          <script>
          function postRequest(url, data) {
            return fetch(url, {
              method: 'POST', 
              mode: 'no-cors',//or 'cors': Though request fails, doPost will execute
              headers: {
              'Accept': '*/*',//**Modified**
              'Content-Type': 'application/x-www-form-urlencoded'
              },
              credentials:'include',//Access Credentials in browser cookies
              body: data
            });
          }
          function onloadfunc(){
          console.log('loading');
          var data = (new URLSearchParams({'a':'xxx','b':'ppp'})).toString();//**MODIFIED**
           postRequest('https://script.google.com/a/WEBAPP/exec', data).then(function(response) {
          //************OPAQUE RESPONSE: Nothing will be received************
           var div = document.getElementById('errorOutput');
              response.text(res=>
                div.innerHTML = "response "+res)
                  console.log("ok");
              }).catch(function(error) {
               var div = document.getElementById('errorOutput');
                div.innerHTML = "error"+error;
              console.log(error);});
          }
          </script>
          <body onload="onloadfunc()">
          <div id="errorOutput"></div>
          </body>
          </html>
      
      

      code.gs

          // Post method
          function doPost(e){
            console.log(JSON.stringify(e,null, 2));
            // check the parameters
            if(typeof e !== 'undefined')
            console.log(e);
            var datavalues = e.parameter; 
            var sheetURL = 'https://docs.google.com/spreadsheets/d/SHEETURL/';
               // Current Active Sheet
               var activeGoogleSheet = SpreadsheetApp.openByUrl(sheetURL);
               var activeSheet = activeGoogleSheet.getActiveSheet();
               // first empty row
               var dataRow = activeSheet.getDataRange().getLastRow()+1;
               // ---------------------------------------------------- //
               // writing data to the sheet
               // ---------------------------------------------------- //
        
                    activeSheet.getRange(dataRow,1).setValue(datavalues.a);
               
                   activeSheet.getRange(dataRow,2).setValue(datavalues.b);
               //WON'T BE RECEIVED BY the post requester anyway// 
             return ContentService.createTextOutput(JSON.stringify(e));
          }
      
      

      这篇关于运行从Google网站发布在Webapp中的功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆