HTML 服務:與伺服器函式通訊

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

google.script.run 是非同步的用戶端 JavaScript API,可讓 HTML 服務網頁呼叫伺服器端 Apps Script 函式。以下範例說明 google.script.run 的基本功能:透過用戶端 JavaScript 在伺服器上呼叫函式

Code.gs

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function doSomething() {
  Logger.log('I was called!');
}

索引.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      google.script.run.doSomething();
    </script>
  </head>
</html>

如果您是以網頁應用程式部署這個指令碼,並造訪該網址,則不會看到任何任何內容,但如果您查看記錄,就會看到呼叫伺服器函式 doSomething()

用戶端對伺服器端函式的呼叫具有非同步性質:在瀏覽器要求伺服器執行 doSomething() 函式後,瀏覽器會立即呼叫下一行程式碼,而不會等待回應。這意味著,伺服器函式呼叫的執行順序可能會按照預期的順序執行。如果您同時執行兩個函式呼叫,就無法知道哪個函式會優先執行;每次載入網頁時,結果可能會有所不同。在這種情況下,成功處理常式失敗處理常式可協助控製程式碼流程。

google.script.run API 可讓你同時呼叫 10 個伺服器函式。如果您在 10 個執行作業期間啟動第 11 次呼叫,系統會延遲伺服器函式,直到有 10 個空間遭到釋出為止。在實際運作時,您通常不必考慮這項限制,尤其是因為大部分的瀏覽器已將數字傳送至相同伺服器的並行要求數低於 10。以 Firefox 為例,上限為 6 個。大部分瀏覽器也會延遲額外的伺服器要求,直到其中一個現有的要求完成為止。

參數和傳回值

您可以使用用戶端的參數呼叫伺服器函式。同樣地,伺服器函式可將值傳回用戶端,做為傳遞至成功處理常式的參數。

法律參數和傳回值是 NumberBooleanStringnull 等 JavaScript 基元,以及由基元、物件和陣列組成的 JavaScript 物件和陣列。頁面中的 form 元素也可以做為參數,但必須是函式的唯一參數,且不代表傳回值。如果您嘗試傳送 DateFunction、 DOM 元素到 form 或其他禁止的類型 (包括物件或陣列中不允許的類型),則要求會失敗。建立循環參照的物件也會失敗,陣列中的未定義欄位會變成 null

請注意,傳遞到伺服器的物件會成為原始的副本。如果伺服器函式收到物件並變更其屬性,用戶端上的屬性不會受到影響。

成功處理常式

由於用戶端程式碼在等待伺服器呼叫完成之前,繼續到下一行,因此 withSuccessHandler(function) 可讓您指定在伺服器回應時執行用戶端回呼函式。如果伺服器函式傳回值,API 會將值做為參數傳遞至新函式。

以下範例顯示伺服器回應時的瀏覽器快訊。請注意,這個伺服器端函式需要授權,因為伺服器端函式正在存取您的 Gmail 帳戶。授權指令碼的最簡單方法,就是在載入網頁前,從指令碼編輯器手動執行 getUnreadEmails() 函式。或者,在部署網頁應用程式時,可以選擇以「存取網頁應用程式的使用者」的身分執行應用程式,在此情況下,系統會在載入應用程式時提示您授權。

Code.gs

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function getUnreadEmails() {
  return GmailApp.getInboxUnreadCount();
}

索引.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      function onSuccess(numUnread) {
        var div = document.getElementById('output');
        div.innerHTML = 'You have ' + numUnread
            + ' unread messages in your Gmail inbox.';
      }

      google.script.run.withSuccessHandler(onSuccess)
          .getUnreadEmails();
    </script>
  </head>
  <body>
    <div id="output"></div>
  </body>
</html>

失敗處理常式

如果伺服器無法回應或擲回錯誤,withFailureHandler(function) 可讓您指定失敗處理常式,而非成功處理常式,並將 Error 物件 (如果有的話) 做為引數傳遞。

根據預設,如未指定失敗處理常式,系統會將失敗記錄至 JavaScript 控制台。如要覆寫此情況,請呼叫 withFailureHandler(null) 或提供不採取任何行動的處理常式。

失敗處理常式的語法與成功處理常式幾乎相同,如以下範例所示。

Code.gs

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function getUnreadEmails() {
  // 'got' instead of 'get' will throw an error.
  return GmailApp.gotInboxUnreadCount();
}

索引.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      function onFailure(error) {
        var div = document.getElementById('output');
        div.innerHTML = "ERROR: " + error.message;
      }

      google.script.run.withFailureHandler(onFailure)
          .getUnreadEmails();
    </script>
  </head>
  <body>
    <div id="output"></div>
  </body>
</html>

使用者物件

您可以呼叫 withUserObject(object) 來指定將要傳遞至處理常式的物件做為第二個參數,在伺服器對多個呼叫重複使用相同成功或失敗處理常式。此「使用者物件」不會與 User 類別混淆,可讓您回應用戶端連線至伺服器的結構定義。由於使用者物件不會傳送至伺服器,因此幾乎可以是任何內容,包括函式、 DOM 元素等,而不受參數呼叫和伺服器呼叫傳回值的限制。然而,使用者物件不能是使用 new 運算子建構的物件。

在這個範例中,按一下其中一個按鈕,就會從伺服器的值更新該按鈕,同時另一個按鈕保持不變,即使其中一個按鈕共用一個成功處理常式也一樣。在 onclick 處理常式中,關鍵字 this 是指 button 本身。

Code.gs

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function getEmail() {
  return Session.getActiveUser().getEmail();
}

索引.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      function updateButton(email, button) {
        button.value = 'Clicked by ' + email;
      }
    </script>
  </head>
  <body>
    <input type="button" value="Not Clicked"
      onclick="google.script.run
          .withSuccessHandler(updateButton)
          .withUserObject(this)
          .getEmail()" />
    <input type="button" value="Not Clicked"
      onclick="google.script.run
          .withSuccessHandler(updateButton)
          .withUserObject(this)
          .getEmail()" />
  </body>
</html>

Forms

如果您呼叫的伺服器函式並使用 form 元素做為參數,則該表單會變成單一物件,並將欄位名稱設為鍵,欄位值則是值。這些檔案的值會轉換為字串,但檔案輸入欄位的內容會成為 Blob 物件。

以下範例處理的是表單,包括檔案輸入欄位,且不需重新載入網頁;這會將檔案上傳至 Google 雲端硬碟,然後在用戶端頁面中列印檔案網址。在 onsubmit 處理常式中,this 關鍵字會參照表單本身。請注意,載入頁面中的所有表單時,preventFormSubmit 會停用預設的提交動作。這可防止網頁因例外狀況而重新導向至不同的網址。

Code.gs

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function processForm(formObject) {
  var formBlob = formObject.myFile;
  var driveFile = DriveApp.createFile(formBlob);
  return driveFile.getUrl();
}

索引.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      // Prevent forms from submitting.
      function preventFormSubmit() {
        var forms = document.querySelectorAll('form');
        for (var i = 0; i < forms.length; i++) {
          forms[i].addEventListener('submit', function(event) {
            event.preventDefault();
          });
        }
      }
      window.addEventListener('load', preventFormSubmit);

      function handleFormSubmit(formObject) {
        google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
      }
      function updateUrl(url) {
        var div = document.getElementById('output');
        div.innerHTML = '<a href="' + url + '">Got it!</a>';
      }
    </script>
  </head>
  <body>
    <form id="myForm" onsubmit="handleFormSubmit(this)">
      <input name="myFile" type="file" />
      <input type="submit" value="Submit" />
    </form>
    <div id="output"></div>
 </body>
</html>

指令碼執行器

您可以將 google.script.run 視為「指令碼執行器」的建構工具。如果在指令碼執行器中加入成功處理常式、失敗處理常式或使用者物件,則不得變更現有的執行器;而是改為執行包含新行為的新指令碼執行器。

您可以使用任何組合、withSuccessHandler()withFailureHandler()withUserObject() 的任意順序。您也可以在已設有值的指令碼執行器上,呼叫任何修改函式。新值只會覆寫先前的值。

這個範例針對所有三個伺服器呼叫設定常見的失敗處理常式,但有兩個不同的成功處理常式:

var myRunner = google.script.run.withFailureHandler(onFailure);
var myRunner1 = myRunner.withSuccessHandler(onSuccess);
var myRunner2 = myRunner.withSuccessHandler(onDifferentSuccess);

myRunner1.doSomething();
myRunner1.doSomethingElse();
myRunner2.doSomething();

私人函式

名稱以底線結尾的伺服器函式會視為私人函式。 google.script 無法呼叫這些函式,其名稱也不會傳送給用戶端。因此,您可以使用這些方法隱藏需要在伺服器上保密的實作詳細資料。google.script 也無法查看程式庫中的函式,以及指令碼在頂層頂層未宣告的函式。

在這個範例中,getBankBalance() 函式可在用戶端程式碼中使用;即使未呼叫原始碼,檢查原始碼的使用者也能探索其名稱。但是,deepSecret_()obj.objectMethod() 函式無法完全向客戶顯示。

Code.gs

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function getBankBalance() {
  var email = Session.getActiveUser().getEmail()
  return deepSecret_(email);
}

function deepSecret_(email) {
 // Do some secret calculations
 return email + ' has $1,000,000 in the bank.';
}

var obj = {
  objectMethod: function() {
    // More secret calculations
  }
};

索引.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      function onSuccess(balance) {
        var div = document.getElementById('output');
        div.innerHTML = balance;
      }

      google.script.run.withSuccessHandler(onSuccess)
          .getBankBalance();
    </script>
  </head>
  <body>
    <div id="output">No result yet...</div>
  </body>
</html>

正在調整 Google Workspace 應用程式內的對話方塊大小

透過用戶端程式碼中的 google.script.host 方法 setWidth(width)setHeight(height) 調整 Google 文件、試算表或表單中的自訂對話方塊。(如要設定對話方塊的初始大小,請使用 HtmlOutput 方法 setWidth(width)setHeight(height))。請注意,調整大小後,對話方塊不會在上層視窗中重新置中,而且無法調整側欄

正在關閉 Google Workspace中的對話方塊和側欄

如果您使用 HTML 服務在 Google 文件、試算表或表單中顯示對話方塊或側欄,就無法透過呼叫 window.close() 關閉介面。您必須呼叫 google.script.host.close()。如需範例,請參閱「將 HTML 做為 Google Workspace 使用者介面提供」一節。

正在將瀏覽器焦點移至 Google Workspace

如要在對話方塊或側欄中,將使用者的瀏覽器焦點切換回 Google 文件、試算表或表單編輯器,只要呼叫 google.script.host.editor.focus() 方法即可。此方法在與文件服務方法 Document.setCursor(position)Document.setSelection(range) 搭配使用時特別實用。