我正在尝试使用Apps Script API执行Apps Script函数。为此,我设置了一个目标脚本,并使用谷歌的指令调用脚本(JavaScript代码(。
我完全按照它的描述,但我得到了以下错误。
-
调用脚本时出错:
ReferenceError:未定义漏洞
-
手动运行函数"时目标脚本出错;getFoldersUnderRoot((">
异常:很抱歉,出现服务器错误。请稍等,然后重试。
函数";getFoldersUnderRoot(("在将目标脚本连接到GCP项目之前运行正常。
感谢任何帮助来指出我做错了什么。
我了解了如何使用应用程序脚本API执行应用程序脚本函数。所以我发布这个答案是为了其他人的利益。此外,我会尝试插入谷歌在其说明中没有提供的缺失信息。
-
目标脚本是一个应用程序脚本(例如"code.gs"(文件,其中包含要执行的所需功能。此脚本必须附加到启用了应用程序脚本API的GCP项目。
-
调用脚本必须是保存在本地文件夹中的html文件,而不是应用程序脚本文件。下面是一个例子";index.html";它调用两个函数";callScriptFunction(("以及";getSheets(("。
<!DOCTYPE html> <html> <head> <title>Google Apps Script API Quickstart</title> <meta charset="utf-8" /> </head> <body> <p>Google Apps Script API Quickstart</p> <!--Add buttons to initiate auth sequence and sign out--> <button id="authorize_button" style="display: none;">Authorize</button> <button id="signout_button" style="display: none;">Sign Out</button> <pre id="content" style="white-space: pre-wrap;"></pre> <script type="text/javascript"> // Client ID and API key from the Developer Console var CLIENT_ID = 'YOUR_CLIENT_ID'; var API_KEY = 'YOUR_API_KEY'; // Array of API discovery doc URLs for APIs used by the quickstart var DISCOVERY_DOCS = ["https://script.googleapis.com/$discovery/rest?version=v1"]; // Authorization scopes required by the API; multiple scopes can be // included, separated by spaces. var SCOPES = 'https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive.readonly'; var authorizeButton = document.getElementById('authorize_button'); var signoutButton = document.getElementById('signout_button'); /** * On load, called to load the auth2 library and API client library. */ function handleClientLoad() { gapi.load('client:auth2', initClient); } /** * Initializes the API client library and sets up sign-in state * listeners. */ function initClient() { gapi.client.init({ apiKey: API_KEY, clientId: CLIENT_ID, discoveryDocs: DISCOVERY_DOCS, scope: SCOPES }).then(function () { // Listen for sign-in state changes. gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus); // Handle the initial sign-in state. updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get()); authorizeButton.onclick = handleAuthClick; signoutButton.onclick = handleSignoutClick; }, function(error) { appendPre(JSON.stringify(error, null, 2)); }); } /** * Called when the signed in status changes, to update the UI * appropriately. After a sign-in, the API is called. */ function updateSigninStatus(isSignedIn) { if (isSignedIn) { authorizeButton.style.display = 'none'; signoutButton.style.display = 'block'; // callScriptFunction(); getSheets(); } else { authorizeButton.style.display = 'block'; signoutButton.style.display = 'none'; } } /** * Sign in the user upon button click. */ function handleAuthClick(event) { gapi.auth2.getAuthInstance().signIn(); } /** * Sign out the user upon button click. */ function handleSignoutClick(event) { gapi.auth2.getAuthInstance().signOut(); } /** * Append a pre element to the body containing the given message * as its text node. Used to display the results of the API call. * * @param {string} message Text to be placed in pre element. */ function appendPre(message) { var pre = document.getElementById('content'); var textContent = document.createTextNode(message + 'n'); pre.appendChild(textContent); } /** * Shows basic usage of the Apps Script API. * * Call the Apps Script API to create a new script project, upload files * to the project, and log the script's URL to the user. */ function callScriptFunction() { var scriptId = "TARGET_SCRIPT_ID"; // Call the Apps Script API run method // 'scriptId' is the URL parameter that states what script to run // 'resource' describes the run request body (with the function name // to execute) gapi.client.script.scripts.run({ 'scriptId': scriptId, 'resource': { 'function': 'getFoldersUnderRoot', 'devMode': true } }).then(function(resp) { var result = resp.result; if (result.error && result.error.status) { // The API encountered a problem before the script // started executing. appendPre('Error calling API:'); appendPre(JSON.stringify(result, null, 2)); } else if (result.error) { // The API executed, but the script returned an error. // Extract the first (and only) set of error details. // The values of this object are the script's 'errorMessage' and // 'errorType', and an array of stack trace elements. var error = result.error.details[0]; appendPre('Script error message: ' + error.errorMessage); if (error.scriptStackTraceElements) { // There may not be a stacktrace if the script didn't start // executing. appendPre('Script error stacktrace:'); for (var i = 0; i < error.scriptStackTraceElements.length; i++) { var trace = error.scriptStackTraceElements[i]; appendPre('t' + trace.function + ':' + trace.lineNumber); } } } else { // The structure of the result will depend upon what the Apps // Script function returns. Here, the function returns an Apps // Script Object with String keys and values, and so the result // is treated as a JavaScript object (folderSet). var folderSet = result.response.result; if (Object.keys(folderSet).length == 0) { appendPre('No folders returned!'); } else { appendPre('Folders under your root folder:'); Object.keys(folderSet).forEach(function(id){ appendPre('t' + folderSet[id] + ' (' + id + ')'); }); } } }); } function getSheets() { // ID of the script to call. Acquire this from the Apps Script editor, // under Publish > Deploy as API executable. var scriptId = "TARGET_SCRIPT_ID"; // Initialize parameters for function call. var sheetId = "SPREADSHEET_ID"; gapi.client.script.scripts.run({ 'scriptId': scriptId, 'resource': { 'function': 'getSheetNames', 'parameters': [sheetId], 'devMode': true } }).then(function(resp) { var result = resp.result; if (result.error && result.error.status) { // The API encountered a problem before the script // started executing. appendPre('Error calling API:'); appendPre(JSON.stringify(result, null, 2)); } else if (result.error) { // The API executed, but the script returned an error. // Extract the first (and only) set of error details. // The values of this object are the script's 'errorMessage' and // 'errorType', and an array of stack trace elements. var error = result.error.details[0]; appendPre('Script error message: ' + error.errorMessage); if (error.scriptStackTraceElements) { // There may not be a stacktrace if the script didn't start // executing. appendPre('Script error stacktrace:'); for (var i = 0; i < error.scriptStackTraceElements.length; i++) { var trace = error.scriptStackTraceElements[i]; appendPre('t' + trace.function + ':' + trace.lineNumber); } } } else { // The structure of the result will depend upon what the Apps // Script function returns. Here, the function returns an Apps // Script Object with String keys and values, and so the result // is treated as a JavaScript object (folderSet). var names = result.response.result; if (Object.keys(names).length == 0) { appendPre('No sheetnames returned!'); } else { appendPre(names); } } }); } </script> <script async defer src="https://apis.google.com/js/api.js" onload="this.onload=function(){};handleClientLoad()" onreadystatechange="if (this.readyState === 'complete') this.onload()"> </script> </body> </html>
-
下面是目标脚本的示例。
function getFoldersUnderRoot() { var root = DriveApp.getRootFolder(); var folders = root.getFolders(); var folderSet = {}; while (folders.hasNext()) { var folder = folders.next(); folderSet[folder.getId()] = folder.getName(); } return folderSet; } function getSheetNames(sheetId) { var ss = SpreadsheetApp.openById(sheetId); var sheets = ss.getSheets(); var names = sheets.map(function(sheet) { return sheet.getName(); }) return names; }
-
从终端更改到工作目录并执行python3-m http.server 8000。打开浏览器并加载";http://localhost:8000/"。授权并继续。
-
您需要将"白名单";http://localhost:8000/"在项目证书
-
您需要在项目的OAuth同意屏幕中添加所需的范围。
我能够执行函数";getSheetNames(("但是";getFoldersUnderRoot(("正在引发错误:从脚本编辑器执行Exception: We're sorry, a server error occurred. Please wait a bit and try again.
也会出现相同的错误。然而;getFoldersUnderRoot(("可在未附加到GCP项目的任何其他脚本上执行