Google sheets API gives Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource

Google sheets API gives Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource

我正在尝试连接一个非常基本的网络,只有 HTML/CSS/JS,google sheet。当我提交表单以将数据上传到 sheet 时,我得到:

Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource.

我一直在阅读这是因为 CORS,但我不知道如何解决它。我的代码非常简单,在 google 脚本中:

function doPost(e){
  let jsonResponse;

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const ws = ss.getSheetByName('web')
  const headers = ws.getRange(1, 1, 1, ws.getLastColumn()).getValues()[0];

  const body = e.postData.contents;
  const bodyJSON = JSON.parse(body);

  jsonResponse = ws.appendRow([bodyJSON.name, bodyJSON.email])    
  return sendJSON_(jsonResponse) 
}

function sendJSON_(jsonResponse) {
  return  ContentService.createTextOutput(JSON.stringify(jsonResponse)).setMimeType(ContentService.MimeType.JSON);
}

我已将我的 HTML 的代码减少到最少及其:

<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <div id='form' class="form">
    <form id="customerForm">
        <input type="text" id="name" placeholder="name">
        <input type="email" id="email" placeholder="Email">
        <button type="submit" id="submitButton">Send</button>
    </form>

    <script>
        function afterSubmit(e){
        url = 'https://script.google.com/macros/s/........../exec'
        var name = document.getElementById('name')
        var email = document.getElementById('email')
        var info = {
            name: name.value,
            email: email.value
        };
        console.log(info);

        fetch(url, {
            method: 'POST',
            cache: 'no-cache',
            redirect: 'follow',
            body: JSON.stringify(info)
        })
        .then(res => res.json())
        .then(res => {
            console.log(res)
        })
          }

        document.getElementById('customerForm').addEventListener('submit', afterSubmit);

    </script>

</body>

</html>

我还检查过,当我将 google sheets 脚本发布为网络应用程序时,我将选项正确设置为: 以以下身份执行应用程序:我 (email@gmail.com) 谁有权访问该应用程序:任何人,甚至是匿名的

我在控制台中得到错误的方法是简单地用浏览器打开 HTML 文件,填写数据并按发送。

修改后的 Apps 脚本

function doPost(e){
  let jsonResponse;

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const ws = ss.getSheetByName('web')
  const headers = ws.getRange(1, 1, 1, ws.getLastColumn()).getValues()[0];

  const body = e.postData.contents;
  const bodyJSON = JSON.parse(body);

  jsonResponse = {"name": bodyJSON.name, "email": bodyJSON.email} // MODIFIED
  ws.appendRow([jsonResponse.name, jsonResponse.email]) // MODIFIED
}
  • 我认为您的主要问题出在这一行

    jsonResponse = ws.appendRow([bodyJSON.name, bodyJSON.email])
    

    如果您看到 appendRow method,它表示 return 类型是 Sheet。所以理论上,没有我的修改,下一行应该return报错了。 Apps 脚本仪表板中的执行说明了什么?也就是说,它可能仍然能够更新 sheet.

    通过此修改,您的 HTML 成功更新了脚本,即使它在浏览器控制台中引发了一堆错误。

  • 你不需要明确地 return 任何东西就可以运行,这就是我在这里省略它的原因。

已修改HTML

function afterSubmit(e) {
  url =
    "https://script.google.com/macros/s/<SCRIPT_ID>/exec";
  var name = document.getElementById("name");
  var email = document.getElementById("email");
  var info = {
    name: name.value,
    email: email.value,
  };
  console.log(info);

  fetch(url, {
    method: "POST",
    cache: "no-cache",
    mode: "no-cors", // to prevent CORS errors
    redirect: "follow",
    body: JSON.stringify(info),
  })
    .then((res) => console.log(res))
    .catch((err) => console.log(err));
  e.preventDefault(); // to prevent form from reloading page
}

document.getElementById("customerForm").addEventListener("submit", afterSubmit);

  • 这里唯一添加的是 mode: "no-cors"
  • 最后的 e.preventDefault() 抑制了我收到的“无法获取”错误,因为表单提交会自动重新加载页面。似乎由于页面重新加载发生在响应返回之前,它只会说“失败”,尽管它已成功更新脚本。
  • 由于 no-cors 参数,returned 对象实际上是空白的,请参阅 response type

如果您想要更有意义的回复,@Tanaike 在之前的帖子中建议使用异步,如下所示:

const fetchData = async (url, info) => {
  var json;
  try {
      const response = await fetch(url, {
        method: 'POST',
        body: JSON.stringify(info),
      });
      if (response != "") json = await response.json();
      console.log('Success:', JSON.stringify(json));
  } catch (e) {
      console.log('Errors:', e.message)
  }
  return json;
}

async function main() {
    const res = await fetchData(url, info);
    console.log(res);
}

main()

这还需要将其添加到 Apps 脚本端:

return ContentService.createTextOutput(JSON.stringify(e)).setMimeType(ContentService.MimeType.JSON);

参考资料