Mesaj iletme

İçerik komut dosyaları uzantı değil bir web sayfası bağlamında çalıştığından genellikle uzantının geri kalanıyla iletişim kurmak için bir yönteme ihtiyaç duyarlar. Örneğin, bir RSS okuyucu uzantısı, içerik komut dosyalarını kullanarak bir sayfada RSS özet akışının olup olmadığını tespit edebilir, ardından arka plandaki sayfaya bu sayfa için bir sayfa işlem simgesi görüntülemek üzere bildirimde bulunabilir.

Uzantılar ve bunların içerik komut dosyaları arasındaki iletişim, mesaj iletme özelliğini kullanarak çalışır. İki taraf da diğer taraftan gönderilen mesajları dinleyebilir ve aynı kanaldan yanıt verebilir. Bir mesaj herhangi bir geçerli JSON nesnesini (boş, boole, sayı, dize, dizi veya nesne) içerebilir. Ortak bir bağlamda birden çok mesaj gönderip almak için tek seferlik istekler için basit bir API ve uzun süreli bağlantılarınıza olanak tanıyan daha karmaşık bir API vardır. Kimliğini biliyorsanız mesajı başka bir uzantıya göndermeniz de mümkündür. Bu, uzantılar arası mesajlar bölümünde açıklanmıştır.

Tek seferlik basit istekler

Uzantınızın başka bir bölümüne yalnızca tek bir mesaj göndermeniz (ve isteğe bağlı olarak yanıt almanız) gerekiyorsa basitleştirilmiş runtime.sendMessage veya tabs.sendMessage öğesini kullanmanız gerekir . Bu , bir içerik komut dosyasından uzantısına veya uzantısına, tek seferlik JSON olarak serileştirilebilir bir mesaj gönderebilmenizi sağlar . İsteğe bağlı bir geri çağırma parametresi, varsa diğer taraftan gelen yanıtı işlemenize olanak tanır.

İçerik komut dosyasından istek gönderme işlemi aşağıdaki gibidir:

chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
  console.log(response.farewell);
});

Uzantıdan içerik komut dosyasına istek gönderme işlemi çok benzerdir. Tek fark, isteğin hangi sekmeye gönderileceğini belirtmenizin gerekmesidir. Bu örnek, seçilen sekmedeki içerik komut dosyasına bir mesajın gönderilmesini göstermektedir.

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
    console.log(response.farewell);
  });
});

Alıcı tarafta, mesajı işlemek için bir runtime.onMessage etkinlik işleyici oluşturmanız gerekir. Bu, içerik komut dosyası veya uzantı sayfasında da aynı şekilde görünür.

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting == "hello")
      sendResponse({farewell: "goodbye"});
  }
);

Yukarıdaki örnekte sendResponse eşzamanlı olarak çağrıldı. sendResponse öğesini eşzamansız olarak kullanmak istiyorsanız onMessage etkinlik işleyiciye return true; ekleyin.

Not: OnMessage etkinliklerini birden çok sayfa dinliyorsa yalnızca belirli bir etkinlik için sendResponse() işlevini ilk çağıran sayfa yanıt göndermede başarılı olur. Bu etkinliğe verilen diğer tüm yanıtlar yoksayılır.
Not: sendResponse geri çağırması yalnızca eşzamanlı olarak kullanılırsa veya etkinlik işleyici eşzamansız yanıt vereceğini belirtmek için true değerini döndürürse geçerlidir. Hiçbir işleyici true (doğru) değerini döndürmezse veya sendResponse geri çağırma işlevi atık toplama işlemi yaparsa sendMessage işlevinin geri çağırması otomatik olarak çağrılır.

Uzun süreli bağlantılar

Bazen tek bir istek ve yanıttan daha uzun süren bir görüşme yapmak kullanışlı olur. Bu durumda, uzun süreli bir kanalı içerik komut dosyanızdan uzantı sayfasına veya runtime.connect ya da tabs.connect'i kullanarak uzun süreli bir kanalı içerik komut dosyanızdan uzantı sayfasına açabilirsiniz . Dilerseniz kanalın bir adı olabilir. Bu ad, farklı bağlantı türlerini ayırt etmenizi sağlar.

Kullanım alanlarından biri otomatik form doldurma uzantısı olabilir. İçerik komut dosyası, belirli bir giriş için uzantı sayfasına giden bir kanalı açabilir ve sayfadaki her giriş öğesi için, form verilerinin doldurulmasını istemek üzere uzantıya bir mesaj gönderebilir. Paylaşılan bağlantı, uzantının içerik komut dosyasından gelen çeşitli mesajlar arasında bağlantı oluşturmayı sürdürebilmesini sağlar.

Bağlantı kurulurken her bir uca bir runtime.Port nesnesi verilir. Bu nesne, bu bağlantı üzerinden mesaj göndermek ve almak için kullanılır.

Kanalı içerik senaryosundan şu şekilde açabilir, mesaj gönderip dinleyebilirsiniz:

var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  if (msg.question == "Who's there?")
    port.postMessage({answer: "Madame"});
  else if (msg.question == "Madame who?")
    port.postMessage({answer: "Madame... Bovary"});
});

Uzantıdan içerik komut dosyasına istek gönderme işlemi çok benzerdir. Tek fark, hangi sekmeye bağlanacağınızı belirtmenizin gerekmesidir. Yukarıdaki örnekte bağlantı kurmak için yapılan aramayı tabs.connect ile değiştirmeniz yeterlidir.

Gelen bağlantıları işlemek için bir runtime.onConnect etkinlik işleyicisi oluşturmanız gerekir. Bu, içerik komut dosyası veya uzantı sayfasında da aynı şekilde görünür. Uzantınızın başka bir bölümü "connect()" çağrısı yaptığında, bağlantı üzerinden mesaj göndermek ve almak için kullanabileceğiniz runtime.Port nesnesiyle birlikte bu etkinlik tetiklenir. Gelen bağlantılara yanıt vermek şu şekilde görünür:

chrome.runtime.onConnect.addListener(function(port) {
  console.assert(port.name == "knockknock");
  port.onMessage.addListener(function(msg) {
    if (msg.joke == "Knock knock")
      port.postMessage({question: "Who's there?"});
    else if (msg.answer == "Madame")
      port.postMessage({question: "Madame who?"});
    else if (msg.answer == "Madame... Bovary")
      port.postMessage({question: "I don't get it."});
  });
});

Bağlantı noktası ömrü

Bağlantı noktaları, uzantının farklı bölümleri arasında iki yönlü bir iletişim yöntemi olarak tasarlanmıştır. Bu iletişimde en küçük parça bir (üst düzey) çerçevedir. tabs.connect, runtime.connect veya runtime.connectNative çağrıldıktan sonra bir Bağlantı Noktası oluşturulur. Bu bağlantı noktası, postMessage üzerinden diğer tarafa mesaj göndermek için hemen kullanılabilir.

Bir sekmede birden fazla çerçeve varsa tabs.connect'in çağrılması, runtime.onConnect etkinliğinin birden fazla kez çağrılmasına (sekmedeki her kare için bir kez) neden olur. Benzer şekilde, runtime.connect kullanılırsa onConnect etkinliği birden çok kez (uzatma işlemindeki her kare için bir kez) tetiklenebilir.

Örneğin, bir bağlantı kapandığında bunu öğrenebilirsiniz. Örneğin, her açık bağlantı noktası için ayrı bir durum mu kullanıyorsunuz? Bunun için runtime.Port.onDisconnect etkinliğini dinleyebilirsiniz. Bu etkinlik, kanalın diğer tarafında geçerli bağlantı noktaları olmadığında tetiklenir. Bu, aşağıdaki durumlarda gerçekleşir:

  • Diğer uçta runtime.onConnect için işleyici yoktur.
  • Bağlantı noktasını içeren sekme kaldırılmış olmalıdır (ör. sekmede geziniliyorsa).
  • connect öğesinin çağrıldığı karenin yüklemesi kaldırıldı.
  • Bağlantı noktasını alan tüm kareler (runtime.onConnect üzerinden) kaldırılmış olur.
  • runtime.Port.disconnect, diğer uç tarafından çağrılır. Bir connect çağrısı, alıcı ucunda birden fazla bağlantı noktasıyla sonuçlanırsa ve bu bağlantı noktalarından herhangi birinde disconnect() çağrılırsa onDisconnect etkinliğinin yalnızca gönderenin bağlantı noktasında tetiklendiğini, diğer bağlantı noktalarında tetiklenmeyeceğini unutmayın.

Uzantılar arası mesajlaşma

Mesajlaşma API'sini, uzantınızdaki farklı bileşenler arasında mesaj göndermeye ek olarak diğer uzantılarla iletişim kurmak için de kullanabilirsiniz. Bu, diğer uzantıların yararlanabileceği herkese açık bir API oluşturmanıza olanak tanır.

Gelen isteklerin ve bağlantıların dinlenmesi dahili destek kaydına benzer. Tek fark, runtime.onMessageExternal veya runtime.onConnectExternal yöntemlerini kullanmanızdır. Her birine bir örnek verelim:

// For simple requests:
chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.id == blocklistedExtension)
      return;  // don't allow this extension access
    else if (request.getTargetData)
      sendResponse({targetData: targetData});
    else if (request.activateLasers) {
      var success = activateLasers();
      sendResponse({activateLasers: success});
    }
  });

// For long-lived connections:
chrome.runtime.onConnectExternal.addListener(function(port) {
  port.onMessage.addListener(function(msg) {
    // See other examples for sample onMessage handlers.
  });
});

Benzer şekilde, bir mesajı başka bir uzantıya göndermek, uzantınız içinde bir mesaj göndermeye benzer. Tek fark, iletişim kurmak istediğiniz uzantının kimliğini iletmeniz gerektiğidir. Örneğin:

// The ID of the extension we want to talk to.
var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
  function(response) {
    if (targetInRange(response.targetData))
      chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
  }
);

// Start a long-running conversation:
var port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);

Web sayfalarından ileti gönderme

Uzantılar arası mesajlaşmaya benzer şekilde, uygulama veya uzantınız normal web sayfalarından mesaj alıp yanıtlayabilir. Bu özelliği kullanmak için ilk olarak manifest.json dosyanızda hangi web siteleriyle iletişim kurmak istediğinizi belirtmeniz gerekir. Örneğin:

"externally_connectable": {
  "matches": ["*://*.example.com/*"]
}

Bu işlem, belirttiğiniz URL kalıplarıyla eşleşen tüm sayfalarda mesajlaşma API'sini gösterir. URL kalıbı en az ikinci düzey bir alan içermelidir. Yani "*", "*.com", "*.co.uk" ve "*.appspot.com" gibi ana makine adı kalıpları yasaktır. Belirli bir uygulama veya uzantıya mesaj göndermek için web sayfasından runtime.sendMessage ya da runtime.connect API'lerini kullanın. Örneğin:

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
      handleError(url);
  });

Uygulama veya uzantınızda, uzantılar arası mesajlaşmaya benzer şekilde runtime.onMessageExternal veya runtime.onConnectExternal API'leri aracılığıyla web sayfalarından gelen mesajları dinleyebilirsiniz. Yalnızca web sayfası bağlantı başlatabilir. Örnek:

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.url == blocklistedWebsite)
      return;  // don't allow this web page access
    if (request.openUrlInEditor)
      openUrl(request.openUrlInEditor);
  });

Yerel mesajlaşma

Uzantılar ve uygulamalar, yerel mesajlaşma ana makinesi olarak kayıtlı yerel uygulamalarla mesaj alışverişi yapabilir. Bu özellik hakkında daha fazla bilgi edinmek için Yerel mesajlaşma başlıklı makaleyi inceleyin.

Güvenlikle ilgili olarak göz önünde bulundurulması gerekenler

İçerik komut dosyaları daha az güvenilir

İçerik komut dosyaları, uzantı arka plan sayfasına göre daha az güvenilirdir (ör. kötü amaçlı bir web sayfası, içerik komut dosyalarının çalıştırıldığı oluşturucu işleminin güvenliğini ihlal edebilir). Bir içerik komut dosyasından gelen mesajların bir saldırgan tarafından oluşturulmuş olabileceğini varsayın ve tüm girişleri doğruladığınızdan ve temizlediğinizden emin olun. İçerik komut dosyasına gönderilen verilerin web sayfasına sızabileceğini varsayın. İçerik komut dosyalarından alınan mesajlar tarafından tetiklenebilecek ayrıcalıklı işlemlerin kapsamını sınırlayın.

Siteler arası komut dosyası çalıştırma

Bir içerik komut dosyasından veya başka bir uzantıdan mesaj alırken komut dosyalarınız, siteler arası komut dosyası çalıştırma kurbanı olmamalarına dikkat etmelidir. Bu öneri, uzantının arka plan sayfası içinde çalışan komut dosyalarının yanı sıra diğer web kaynakları içinde çalışan içerik komut dosyaları için de geçerlidir. Özellikle aşağıdakiler gibi tehlikeli API'leri kullanmaktan kaçının:

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be evaluating an evil script!
  var resp = eval("(" + response.farewell + ")");
});
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be injecting a malicious script!
  document.getElementById("resp").innerHTML = response.farewell;
});

Bunun yerine, komut dosyalarını çalıştırmayan daha güvenli API'leri tercih edin:

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // JSON.parse does not evaluate the attacker's scripts.
  var resp = JSON.parse(response.farewell);
});
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // innerText does not let the attacker inject HTML elements.
  document.getElementById("resp").innerText = response.farewell;
});

Örnekler

examples/api/messaging dizininde mesaj üzerinden basit iletişim örneklerini bulabilirsiniz. Yerel mesajlaşma örneği, bir Chrome uygulamasının yerel bir uygulamayla nasıl iletişim kurabileceğini gösterir. Daha fazla örnek ve kaynak kodunu görüntüleme konusunda yardım için Örnekler bölümüne bakın.