Pesan yang diteruskan

Karena skrip konten berjalan dalam konteks laman web dan bukan ekstensi, skrip sering kali memerlukan beberapa berkomunikasi dengan ekstensi lainnya. Misalnya, ekstensi pembaca RSS mungkin menggunakan skrip konten untuk mendeteksi keberadaan feed RSS pada halaman, lalu memberitahukan halaman latar belakang guna menampilkan ikon tindakan halaman untuk halaman tersebut.

Komunikasi antara ekstensi dan skrip kontennya berjalan dengan menggunakan penerusan pesan. Keduanya dapat mendengarkan pesan yang dikirim dari pihak lain, dan merespons di saluran yang sama. Pesan dapat berisi objek JSON yang valid (null, boolean, angka, string, array, atau objek). Ada cara untuk API untuk permintaan satu kali dan API lebih kompleks yang memungkinkan Anda memiliki jangka panjang koneksi untuk bertukar beberapa pesan dengan konteks bersama. Dimungkinkan juga untuk mengirim pesan ke ekstensi lain jika Anda mengetahui ID-nya, yang tercakup dalam ekstensi silang pesan Anda.

Permintaan satu kali yang sederhana

Jika Anda hanya perlu mengirim satu pesan ke bagian lain dari ekstensi (dan secara opsional mendapatkan respons kembali), Anda harus menggunakan runtime.sendMessage atau tabs.sendMessage yang disederhanakan . Hal ini memungkinkan Anda mengirim pesan JSON satu kali yang dapat diserialisasi dari skrip konten ke ekstensi , atau sebaliknya sebaliknya . Parameter callback opsional memungkinkan Anda menangani respons dari tersebut, jika ada.

Pengiriman permintaan dari skrip konten akan terlihat seperti ini:

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

Mengirim permintaan dari ekstensi ke skrip konten terlihat sangat mirip, kecuali bahwa Anda harus menentukan tab mana yang akan dituju. Contoh ini menunjukkan pengiriman pesan ke skrip konten di tab yang dipilih.

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

Di pihak penerima, Anda perlu menyiapkan pemroses peristiwa runtime.onMessage untuk menangani untuk membuat pesan email baru. Tampilannya akan terlihat sama jika dilihat dari skrip konten atau halaman ekstensi.

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

Pada contoh di atas, sendResponse dipanggil secara sinkron. Jika Anda ingin menggunakan sendResponse, tambahkan return true; ke pengendali peristiwa onMessage.

Catatan: Jika beberapa halaman memproses peristiwa onMessage, hanya halaman pertama yang memanggil sendResponse() untuk peristiwa tertentu yang akan berhasil mengirim respons. Semua respons lain terhadap peristiwa tersebut akan diabaikan.
Catatan: Callback sendResponse hanya valid jika digunakan secara sinkron, atau jika pengendali peristiwa menampilkan true untuk menunjukkan bahwa callback tersebut akan merespons secara asinkron. Callback fungsi sendMessage akan dipanggil secara otomatis jika tidak ada pengendali yang menampilkan benar atau jika callback sendResponse dibersihkan sampah memori.

Koneksi jangka panjang

Terkadang ada baiknya melakukan percakapan yang berlangsung lebih dari satu permintaan dan respons. Dalam hal ini, Anda dapat membuka saluran berumur panjang dari skrip konten ke halaman ekstensi , atau sebaliknya, menggunakan runtime.connect atau tabs.connect . Channel tersebut dapat opsional memiliki nama, memungkinkan Anda untuk membedakan antara berbagai jenis koneksi.

Satu kasus penggunaan mungkin berupa ekstensi pengisian formulir otomatis. Skrip konten dapat membuka channel untuk halaman ekstensi untuk login tertentu, dan mengirim pesan ke ekstensi untuk setiap input di laman untuk meminta data formulir yang akan diisi. Koneksi bersama memungkinkan ekstensi untuk mempertahankan status bersama yang menautkan beberapa pesan yang berasal dari skrip konten.

Saat membuat koneksi, setiap ujung diberi objek runtime.Port yang digunakan untuk mengirim dan menerima pesan melalui koneksi itu.

Berikut ini cara membuka channel dari skrip konten, serta mengirim dan mendengarkan pesan:

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

Mengirim permintaan dari ekstensi ke skrip konten terlihat sangat mirip, kecuali bahwa Anda harus menentukan tab mana yang akan disambungkan. Cukup ganti panggilan untuk menghubungkan dalam contoh di atas dengan tabs.connect.

Untuk menangani koneksi masuk, Anda perlu menyiapkan peristiwa runtime.onConnect pemroses. Tampilan ini terlihat sama dari skrip konten atau halaman ekstensi. Ketika bagian lain dari ekstensi memanggil "connect()", peristiwa ini akan diaktifkan, bersama dengan objek runtime.Port yang dapat Anda gunakan untuk mengirim dan menerima pesan melalui koneksi. Berikut tampilan untuk merespons koneksi masuk:

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."});
  });
});

Masa aktif port

Porta dirancang sebagai metode komunikasi dua arah antara bagian yang berbeda dari ekstensi {i>frame<i} (tingkat atas) dipandang sebagai bagian terkecil. Setelah memanggil tabs.connect, runtime.connect atau runtime.connectNative, atau Port akan dibuat. Porta ini dapat segera digunakan untuk mengirim pesan ke sisi lain melalui postMessage.

Jika ada beberapa frame dalam satu tab, memanggil tabs.connect akan menghasilkan beberapa pemanggilan peristiwa runtime.onConnect (satu kali untuk setiap frame di tab). Demikian pula, jika runtime.connect akan digunakan, maka peristiwa onConnect mungkin akan diaktifkan beberapa kali (sekali untuk setiap dalam proses ekstensi).

Anda mungkin ingin mengetahui kapan koneksi ditutup, misalnya jika Anda mempertahankan status untuk setiap porta yang terbuka. Untuk itu, Anda dapat memproses peristiwa runtime.Port.onDisconnect. Ini peristiwa diaktifkan saat tidak ada port yang valid di sisi lain saluran. Hal ini terjadi di situasi berikut:

  • Tidak ada pemroses untuk runtime.onConnect di sisi lain.
  • Tab yang berisi port dihapus muatannya (misalnya, jika tab dibuka).
  • Frame tempat connect dipanggil telah dibongkar.
  • Semua frame yang menerima port (melalui runtime.onConnect) telah dihapus muatannya.
  • runtime.Port.disconnect dipanggil oleh sisi satunya. Perhatikan bahwa jika hasil panggilan connect di beberapa port di ujung penerima, dan disconnect() dipanggil di salah satu port ini, lalu peristiwa onDisconnect hanya diaktifkan pada port pengirim, dan bukan di port lainnya.

Pesan lintas ekstensi

Selain mengirim pesan di antara komponen yang berbeda di ekstensi, Anda dapat menggunakan untuk berkomunikasi dengan ekstensi lain. Hal ini memungkinkan Anda mengekspos API publik yang dapat dimanfaatkan oleh ekstensi.

Memproses permintaan dan koneksi masuk mirip dengan kasus internal, kecuali Anda menggunakan Metode runtime.onMessageExternal atau runtime.onConnectExternal. Berikut adalah contoh masing-masing:

// 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.
  });
});

Demikian pula, mengirim pesan ke ekstensi lain mirip dengan mengirim pesan dalam ekstensi Anda. Satu-satunya perbedaan adalah Anda harus meneruskan ID ekstensi yang ingin diajak berkomunikasi. Contoh:

// 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(...);

Mengirim pesan dari halaman web

Mirip dengan pesan lintas ekstensi, aplikasi atau ekstensi Anda dapat menerima dan merespons pesan dari laman web biasa. Untuk menggunakan fitur ini, Anda harus terlebih dahulu menentukan di manifest.json situs web mana yang ingin Anda ajak berkomunikasi. Contoh:

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

Tindakan ini akan mengekspos API pesan ke halaman mana pun yang cocok dengan pola URL yang Anda tentukan. URL pola harus berisi setidaknya domain level kedua - yaitu, pola nama host seperti "*", "*.com", "*.co.uk", dan "*.appspot.com" dilarang. Dari laman web tersebut, gunakan runtime.sendMessage atau runtime.connect API untuk mengirim pesan ke aplikasi atau . Contoh:

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

Dari aplikasi atau ekstensi, Anda dapat mendengarkan pesan dari halaman web melalui runtime.onMessageExternal atau runtime.onConnectExternal API, mirip dengan lintas ekstensi pesan. Hanya halaman web yang dapat memulai koneksi. Berikut ini contohnya:

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

Pesan native

Ekstensi dan aplikasi dapat bertukar pesan dengan aplikasi asli yang terdaftar sebagai host pesan native. Untuk mempelajari fitur ini lebih lanjut, lihat Pesan native.

Pertimbangan keamanan

Skrip konten kurang tepercaya

Skrip konten kurang tepercaya dibandingkan halaman latar belakang ekstensi (misalnya, web berbahaya halaman mungkin dapat menyusupi proses perender tempat skrip konten berjalan). Asumsikan bahwa pesan dari skrip konten mungkin telah dibuat oleh penyerang dan pastikan untuk memvalidasi dan membersihkan semua input. Asumsikan ada data yang dikirim ke skrip konten mungkin bocor ke halaman web. Batasi cakupan tindakan hak istimewa yang dapat dipicu oleh pesan yang diterima dari konten skrip.

Pembuatan skrip antarsitus

Saat menerima pesan dari skrip konten atau ekstensi lain, skrip harus berhati-hati agar tidak menjadi korban pembuatan skrip lintas situs. Saran ini berlaku untuk skrip yang berjalan di dalam laman latar belakang ekstensi serta skrip konten yang berjalan di dalam asal web lainnya. Secara khusus, hindari penggunaan API berbahaya seperti yang di bawah ini:

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

Sebagai gantinya, pilih API yang lebih aman yang tidak menjalankan skrip:

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

Contoh

Anda dapat menemukan contoh komunikasi sederhana melalui pesan di examples/api/Messaging saat ini. Contoh pesan native menunjukkan cara aplikasi Chrome dapat berkomunikasi dengan aplikasi native tersebut. Untuk mengetahui contoh lainnya dan bantuan dalam melihat kode sumber, lihat Contoh.