HTML Hizmeti: Sunucu İşlevleri ile İletişim

google.script.run, HTML hizmeti sayfalarının sunucu tarafı Apps Komut Dosyası işlevlerini çağırmasına olanak tanıyan eşzamansız bir istemci tarafı JavaScript API'dir. Aşağıdaki örnekte google.script.run ürününün en temel işlevi gösterilmektedir. Bu işlev, istemci taraflı JavaScript'ten sunucudaki bir işlevi çağırır.

Code.gs

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

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

Index.html

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

Bu komut dosyasını bir web uygulaması olarak dağıtır ve URL'sini ziyaret ederseniz hiçbir şey görmezsiniz, ancak günlükleri görüntülerseniz sunucu işlevinin doSomething() çağrıldığını görürsünüz.

Sunucu tarafı işlevlere yapılan istemci tarafı çağrılar eşzamansızdır: Tarayıcı, sunucunun doSomething() işlevini çalıştırmasını istedikten sonra, tarayıcı yanıt beklemeden hemen sonraki kod satırına devam eder. Bu, sunucu işlevi çağrılarının beklediğiniz sırada yürütülmeyebileceği anlamına gelir. Aynı anda iki işlev çağrısı yaparsanız hangi işlevin önce çalışacağını bilmenin bir yolu yoktur. Sonuç, sayfayı her yüklediğinizde farklı olabilir. Bu durumda, başarı işleyiciler ve hata işleyiciler kod akışınızı kontrol etmenize yardımcı olur.

google.script.run API, sunucu işlevlerine aynı anda 10 çağrı yapılmasına izin verir. 10 numaralı arama hâlâ çalışırken 11. çağrı yaparsanız sunucu işlevi, 10 noktadan biri serbest bırakılana kadar geciktirilir. Pratikte, özellikle çoğu tarayıcı aynı sunucuya eşzamanlı istek sayısını 10'dan düşük bir sayıyla zaten sınırladığından, bu kısıtlama hakkında nadiren düşünmeniz gerekir. Örneğin, Firefox'ta sınır 6'dır. Benzer şekilde, çoğu tarayıcı fazla sunucu isteklerini mevcut isteklerden biri tamamlanana kadar geciktirir.

Parametreler ve döndürülen değerler

İstemciden parametreleri kullanarak bir sunucu işlevini çağırabilirsiniz. Benzer şekilde, bir sunucu işlevi de başarı işleyiciye iletilen bir parametre olarak istemciye bir değer döndürebilir.

Yasal parametreler ve dönüş değerleri Number, Boolean, String veya null gibi temel JavaScript öğelerinin yanı sıra temel öğelerden, nesnelerden ve dizilerden oluşan JavaScript nesneleri ve dizileridir. Sayfa içindeki bir form öğesi de parametre olarak yasaldır ancak işlevin tek parametresi olmalıdır ve döndürülen değer olarak yasal değildir. Bir Date, Function, form dışında DOM öğesi veya başka bir yasak türü (nesnelerin veya dizilerin içindeki yasaklı türler dahil) iletmeye çalışırsanız istekler başarısız olur. Dairesel referanslar oluşturan nesneler de başarısız olur ve dizilerdeki tanımlanmamış alanlar null haline gelir.

Sunucuya iletilen bir nesnenin, orijinalin kopyası haline geleceğini unutmayın. Bir sunucu işlevi, bir nesneyi alır ve özelliklerini değiştirirse istemcideki özellikler etkilenmez.

Başarı işleyiciler

İstemci tarafı kodu, bir sunucu çağrısının tamamlanmasını beklemeden sonraki satıra devam ettiğinden, withSuccessHandler(function) sunucu yanıt verdiğinde çalışacak bir istemci tarafı geri çağırma işlevi belirtmenize olanak tanır. Sunucu işlevi bir değer döndürürse API, değeri yeni işleve parametre olarak iletir.

Aşağıdaki örnekte, sunucu yanıt verdiğinde bir tarayıcı uyarısı gösterilmektedir. Sunucu tarafı işlevi Gmail hesabınıza eriştiğinden bu kod örneğinin yetkilendirme gerektirdiğini unutmayın. Komut dosyasını yetkilendirmenin en basit yolu, sayfayı yüklemeden önce getUnreadEmails() işlevini komut dosyası düzenleyiciden manuel olarak çalıştırmaktır. Alternatif olarak, web uygulamasını dağıtırken uygulamayı "web uygulamasına erişen kullanıcı" olarak yürütmeyi de seçebilirsiniz. Bu durumda, uygulamayı yüklerken yetkilendirme istenir.

Code.gs

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

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

Index.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>

Hata işleyiciler

Sunucunun yanıt vermemesi veya hata vermesi durumunda withFailureHandler(function), başarı işleyici yerine bir hata işleyici belirtmenize olanak tanır. Bu seçenekte, Error nesnesi (varsa) bağımsız değişken olarak iletilir.

Varsayılan olarak, bir hata işleyici belirtmezseniz hatalar JavaScript konsoluna kaydedilir. Bunu geçersiz kılmak için withFailureHandler(null) yöntemini çağırın veya hiçbir şey yapmayan bir hata işleyici sağlayın.

Bu örnekte gösterildiği gibi, hata işleyicilerin söz dizimi, başarı işleyicilerle neredeyse aynıdır.

Code.gs

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

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

Index.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>

Kullanıcı nesneleri

İşleyiciye ikinci parametre olarak iletilecek bir nesneyi belirtmek için withUserObject(object) yöntemini çağırarak sunucuya yapılan birden fazla çağrıda aynı başarılı veya başarısız işleyiciyi yeniden kullanabilirsiniz. User sınıfıyla karıştırılmaması gereken bu "kullanıcı nesnesi", istemcinin sunucuyla iletişim kurduğu bağlama yanıt verebilmenizi sağlar. Kullanıcı nesneleri sunucuya gönderilmediğinden, parametreler ve sunucu çağrıları için döndürülen değerler üzerinde kısıtlamalar olmadan işlevler, DOM öğeleri vb. dahil olmak üzere neredeyse her şey olabilir. Bununla birlikte kullanıcı nesneleri, new operatörüyle oluşturulan nesneler olamaz.

Bu örnekte, iki düğmeden biri tıklandığında o düğme sunucudaki bir değerle güncellenir. Diğer düğmede tek bir başarılı işleyici bulunmasına rağmen diğer düğme değiştirilmeden bırakılır. onclick işleyicinin içinde this anahtar kelimesi, button'nin kendisine referansta bulunur.

Code.gs

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

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

Index.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>

Formlar

Parametre olarak form öğesine sahip bir sunucu işlevini çağırırsanız form, alan adlarını anahtar, alan değerlerini değer olarak içeren tek bir nesne haline gelir. Blob nesnesi haline gelen dosya girişi alanlarının içerikleri dışında, değerlerin tümü dizeye dönüştürülür.

Bu örnekte, dosya giriş alanı içeren bir form sayfayı yeniden yüklenmeden işlenir; dosya Google Drive'a yüklenir ve daha sonra dosyanın URL'si istemci tarafındaki sayfaya yazdırılır. onsubmit işleyicide this anahtar kelimesi, formun kendisini ifade eder. Sayfadaki tüm formlar yüklendiğinde, varsayılan gönderme işleminin preventFormSubmit tarihine kadar devre dışı bırakılacağını unutmayın. Bu, istisna durumunda sayfanın yanlış bir URL'ye yönlendirme yapmasını önler.

Code.gs

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

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

Index.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>

Komut dosyası çalıştırıcıları

google.script.run uygulamasını bir "komut dosyası çalıştırıcı" için bir derleyici olarak düşünebilirsiniz. Bir komut dosyası çalıştırıcıya bir başarı işleyici, hata işleyici veya kullanıcı nesnesi eklerseniz mevcut çalıştırıcıyı değiştirmiş olmazsınız, bunun yerine yeni davranışa sahip yeni bir komut dosyası çalıştırıcı elde edersiniz.

İstediğiniz kombinasyonu ve withSuccessHandler(), withFailureHandler() ve withUserObject() değerlerini istediğiniz sırada kullanabilirsiniz. Önceden belirlenmiş bir değere sahip bir komut dosyası çalıştırıcıdaki değiştirme işlevlerinden herhangi birini de çağırabilirsiniz. Yeni değer yalnızca önceki değeri geçersiz kılar.

Bu örnekte, üç sunucu çağrısının tümü için ortak bir hata işleyicisi ayarlanır, ancak iki ayrı başarılı işleyici bulunur:

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

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

Özel işlevler

Adları alt çizgiyle biten sunucu işlevleri gizli olarak kabul edilir. Bu işlevler google.script tarafından çağrılamaz ve adları hiçbir zaman istemciye gönderilmez. Böylece, sunucuda gizli tutulması gereken uygulama ayrıntılarını gizlemek için bunları kullanabilirsiniz. google.script, kitaplıklar içindeki işlevleri ve komut dosyasının üst düzeyinde bildirilmemiş işlevleri de göremez.

Bu örnekte, getBankBalance() işlevi istemci kodunda mevcuttur. Kaynak kodunuzu inceleyen bir kullanıcı, siz çağırmasanız bile kaynak kodunuzu keşfedebilir. Ancak deepSecret_() ve obj.objectMethod() işlevleri istemci tarafından tamamen görünmez.

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
  }
};

Index.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>

Uygulamalardaki Google Workspace iletişim kutuları yeniden boyutlandırılıyor

Google Dokümanlar, E-Tablolar veya Formlar'daki özel iletişim kutuları, istemci tarafı kodundaki google.script.host yöntemlerinin setWidth(width) veya setHeight(height) çağrılmasıyla yeniden boyutlandırılabilir. (Bir iletişim kutusunun ilk boyutunu ayarlamak için HtmlOutput setWidth(width) ve setHeight(height) yöntemlerini kullanın.) Yeniden boyutlandırıldığında iletişim kutularının üst pencerede yeniden ortalanmadığını ve kenar çubuklarını yeniden boyutlandırmanın mümkün olmadığını unutmayın.

Google Workspaceiçindeki iletişim kutuları ve kenar çubukları kapatılıyor

Google Dokümanlar, E-Tablolar veya Formlar'da iletişim kutusu ya da kenar çubuğu görüntülemek için HTML hizmetini kullanıyorsanız window.close() yöntemini çağırarak arayüzü kapatamazsınız. Bunun yerine, google.script.host.close() işlevini çağırmanız gerekir. Örnek için HTML'yi Google Workspace kullanıcı arayüzü olarak sunma konulu bölüme bakın.

Tarayıcı odağı Google Workspacekonumuna taşınıyor

Kullanıcının tarayıcısındaki odağı bir iletişim kutusundan veya kenar çubuğundan Google Dokümanlar, E-Tablolar veya Formlar düzenleyicisine geri döndürmek için ilgili yöntemi google.script.host.editor.focus() çağırmanız yeterlidir. Bu yöntem özellikle Belge hizmeti Document.setCursor(position) ve Document.setSelection(range) ile birlikte kullanıldığında kullanışlıdır.