【问题标题】:Assign object from google scripts to local variable using AJAX使用 AJAX 将对象从谷歌脚本分配给局部变量
【发布时间】:2020-05-18 09:08:07
【问题描述】:

我编写了一个自定义的 Google 脚本,它为我输出一个对象,我希望能够调用它并将它分配给一个变量,然后用于在网站上显示数据。

HTML 标题:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
    <title>JQVMap - World Map</title>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
    <link href="../dist/jqvmap.css" media="screen" rel="stylesheet" type="text/css" />
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
    <script type="text/javascript" src="../dist/jquery.vmap.js"></script>
    <script type="text/javascript" src="../dist/maps/jquery.vmap.world.js" charset="utf-8"></script>
    <script type="text/javascript" src="js/jquery.vmap.sampledata.deaths.js"></script>
    <script type="text/javascript" src="js/jquery.vmap.sampledata.infected.js"></script>
    <script>
        jQuery(document).ready(function () {
            jQuery('#vmap').vectorMap({
                map: 'world_en',
                backgroundColor: '#333333',
                color: '#ffffff',
                hoverOpacity: 0.8,
                selectedColor: '#3498DB',
                enableZoom: true,
                showTooltip: true,
                scaleColors: ['#F3A291', '#FF4F3B'],
                values: infected_data,
                normalizeFunction: 'polynomial',
                onLabelShow: function (event, label, code) {
                    label.html('<div class="map-tooltip"><h1 class="header"> ' + label.html() + '</h1><p class="description">Infected: ' + infected_data[code] + '</p><p class="description">Deaths: ' + death_data[code] + '</p></div>');
                }
            });
        });
    </script>
</head>

Google 脚本文件:

function doGet() {
    var result = {};
    var infected = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data').getDataRange().getValues();
    var death = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data').getDataRange().getValues();
    result = makeObject(infected);

    return ContentService.createTextOutput(JSON.stringify(result)).setMimeType(ContentService.MimeType.JSON);
}

function makeObject(multiArr) {
    var obj = {};
    var countrystats = {};
    var headers = multiArr.shift();

    for (var i = 0; i < headers.length; i++) {
        countrystats[i] = multiArr.map(function (app) {
            return app[i];
        })
    }

    for (var m = 0; m < countrystats[1].length; m++) {
        obj[countrystats[1][m]] = 0;
    }

    for (var j = 0; j < countrystats[1].length; j++) {
        var TempVar;
        TempVar = obj[countrystats[1][j]];
        obj[countrystats[1][j]] = TempVar + countrystats[3][j];

    }

    return obj;
}

Google 脚本输出(使用 JSON View chrome 扩展):

{
cn: 8134,
th: 23,
mo: 7,
us: 5,
jp: 11,
kr: 4,
sg: 10,
vn: 2,
fr: 5,
np: 1,
my: 8,
ca: 3,
ci: 1,
lk: 1,
au: 9,
de: 4,
fn: 1
}

这是一个带有我想要的对象/数据的公共链接(上面显示的相同对象):网络应用程序:https://script.google.com/macros/s/AKfycbzsyQNJwDvQc5SvNGEDZZOoNI3XxNar9PA9sRucZx7mgzfWpFQ/exec

所以基本上任何使用它的人都应该能够访问它。我只需要一种将数据分配给本地 JS 变量的方法。 google 表格脚本作为网络应用程序发布。如果我没记错的话,有一个设置允许任何人,甚至匿名访问它。

这是我对 AJAX 请求的尝试:

 var url = "https://script.google.com/macros/s/AKfycbzsyQNJwDvQc5SvNGEDZZOoNI3XxNar9PA9sRucZx7mgzfWpFQ/exec";


      var infected_data = jQuery.ajax({
        crossDomain: true,
        url: url,
        method: "GET",
        //dataType: "jsonp"
      });

如果我取消注释 jsonp,我会收到错误:

jquery-1.11.3.min.js:5 跨域读取阻塞 (CORB) 阻止了 MIME 类型 application/json 的跨域响应 https://script.googleusercontent.com/macros/echo?user_content_key=JXkCjiJjhcjndRREjoGyVNkZNkD-HvKpEPkpicQBm9nR9OkxjGXdYuOPsLxbJf-B9Rgifl5NWMtzgjfVGuMdGxTJrjKnRpdcOJmA1Yb3SEsKFZqtv3DaNYcMrmhZHmUMWojr9NvTBuBLhyHCd5hHazTNYZyoqG0ZuVXpWSNdoeLErB4AfUCNPKJHgELe5WaAmN5SlwIhonlWkkbFzR8kUwjKrMtdq9u-YqreD7W_KJ_aVqKVBTehAuogPCoZCfVc4yJf5ieDCdMDbXQ8FZZq8iSedsk1Px1LnPBLM8W-ZRcknnbJNT8dS525XG1pNEBR&lib=Mw_Scq3iKhByBS86NJpd_CngcdEShCw7K。详情请见https://www.chromestatus.com/feature/5629709824032768

如果我删除它,我不会收到任何错误。但是,我仍然看不到交互式地图(我的应用程序)上的数据。

使用 Fetch:

const url = "https://script.google.com/macros/s/AKfycbzsyQNJwDvQc5SvNGEDZZOoNI3XxNar9PA9sRucZx7mgzfWpFQ/exec";

  // Declare an async function
  const getData = async () => {
  // Use the await keyword to let JS know this variable has some latency so it should wait for it to be filled 
  // When the variable is fetched, use the .then() callback to carry on 
    const DataJSON = await fetch(url).then(response => 
      response.json()
    ).then(parsedResponse => parsedResponse)
  
    return await DataJSON
  };
  
  console.log(getData());
  var infected_data = getData();

将对象中的整数转换为字符串 对象需要采用如下格式:

var infected_data = {
  cn: "83",
  th: "0",
  mo: "0",
  au: "0",
  sg: "0",
  tw: "0",
  us: "0",
  jp: "0",
  my: "0",
  kr: "0",
  fx: "0",
  vn: "0",
  kh: "0",
  ca: "0",
  ci: "0",
  np: "0",
  lk: "0",
  
};

【问题讨论】:

  • Sending jsonp 是最简单的方法。
  • 这样的? : 这样我又遇到了 CORB 问题。
  • 是的。您的doGet() 也应该相应地进行修改。将带有前缀的 json 字符串化并将 mime 设置为 JavaScript(不要忘记发布新版本并部署)。
  • 完美,我让它与您的方法和 Max Steenbergen 的方法一起使用。如果您看一下上面(更新的帖子),我相信我需要的最后一步是将整数值转换为字符串。有什么想法吗?
  • 别以为有什么捷径可走。循环并转换为字符串。后续问题最好作为新问题提出。

标签: javascript google-apps-script cross-origin-read-blocking


【解决方案1】:

回答将整数转换为字符串的问题: 试试这样的:

function toString(o) {
  Object.keys(o).forEach(k => {
    if (typeof o[k] === 'object') {
      return toString(o[k]);
    }

    o[k] = '' + o[k];
  });

  return o;
}

【讨论】:

    【解决方案2】:

    假设数据不敏感,可以使用jsonp绕过cors:

    服务器端:

    return ContentService.createTextOutput("infect(" +JSON.stringify(result)+ ")").setMimeType(ContentService.MimeType.JAVASCRIPT);
    

    客户端:

    <script>function infect(data){ infectedData =  data }</script>
    <script src="URL_OF_YOUR_SCRIPT"></script>
    

    参考资料:

    【讨论】:

      【解决方案3】:

      您可能会遇到异步调用的问题,这意味着您在数据实际从 Google 服务器返回之前读取数据。尝试使用promisesfetch API

      const url = "https://script.google.com/macros/s/AKfycbzsyQNJwDvQc5SvNGEDZZOoNI3XxNar9PA9sRucZx7mgzfWpFQ/exec";
      
      // Declare an async function
      const getData = async () => {
      // Use the await keyword to let JS know this variable has some latency so it should wait for it to be filled 
      // When the variable is fetched, use the .then() callback to carry on 
        const DataJSON = await fetch(url).then(response => 
          response.json()
        ).then(parsedResponse => parsedResponse)
      
        return await DataJSON
      };
      
      console.log(await getData())
      

      【讨论】:

      • 看看更新后的帖子,这是我在控制台中得到的。似乎仍然没有给出数据,或者它可能只是其他一些奇怪的格式。
      • 糟糕,我看到了对象及其所有数据!!!甜的!这似乎运作良好。现在我认为唯一的问题是它没有正确分配给 Var Infected_Data。编辑:我忘了,值必须是字符串,而不是数字。有没有一种快速简便的方法来转换它们。
      • 我怎样才能只访问 promise 中的对象?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-20
      • 1970-01-01
      • 2012-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多