Mesajlaşma API'leri, uzantınızla ilişkili bağlamlarda çalışan farklı komut dosyaları arasında iletişim kurmanıza olanak tanır. Bu, hizmet çalışanınız, chrome-extension://pages ve içerik komut dosyaları arasındaki iletişimi içerir. Örneğin, bir RSS okuyucu uzantısı, bir sayfada RSS özet akışının varlığını algılamak için içerik komut dosyalarını kullanabilir ve ardından hizmet çalışanını, söz konusu sayfanın işlem simgesini güncellemesi için bilgilendirebilir.
İki ileti geçirme API'si vardır: biri tek seferlik istekler için, diğeri ise birden fazla ileti gönderilmesine olanak tanıyan uzun süreli bağlantılar için daha karmaşıktır.
Uzantılar arasında mesaj gönderme hakkında bilgi edinmek için Uzantılar arası mesajlar bölümüne bakın.
Tek seferlik istekler
Uzantınızın başka bir bölümüne tek bir mesaj göndermek ve isteğe bağlı olarak yanıt almak için runtime.sendMessage()
veya tabs.sendMessage()
işlevini çağırın.
Bu yöntemler, içerik komut dosyasından uzantıya veya uzantıdan içerik komut dosyasına tek seferlik JSON olarak serileştirilebilen bir mesaj göndermenize olanak tanır. Her iki API de alıcı tarafından sağlanan yanıta çözümlenen bir Promise döndürür.
İçerik komut dosyasından istek gönderme işlemi şu şekilde görünür:
content-script.js:
(async () => {
const response = await chrome.runtime.sendMessage({greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();
Yanıtlar
Bir mesajı dinlemek için chrome.runtime.onMessage
etkinliğini kullanın:
// Event listener
function handleMessages(message, sender, sendResponse) {
fetch(message.url)
.then((response) => sendResponse({statusCode: response.status}))
// Since `fetch` is asynchronous, must return an explicit `true`
return true;
}
chrome.runtime.onMessage.addListener(handleMessages);
// From the sender's context...
const {statusCode} = await chrome.runtime.sendMessage({
url: 'https://example.com'
});
Etkinlik işleyicisi çağrıldığında üçüncü parametre olarak bir sendResponse
işlevi iletilir. Bu, yanıt vermek için çağrılabilen bir işlevdir. Varsayılan olarak, sendResponse
geri çağırma işlevi senkron olarak çağrılmalıdır. sendResponse
öğesine iletilen değeri almak için eşzamansız çalışma yapmak istiyorsanız etkinlik işleyiciden kesinlikle true
değişmezini (yalnızca doğru değeri değil) döndürmelisiniz. Bu işlem, sendResponse
aranana kadar mesaj kanalını diğer uç için açık tutar.
sendResponse
işlevini parametre olmadan çağırırsanız yanıt olarak null
gönderilir.
Birden fazla sayfa onMessage
etkinliklerini dinliyorsa yanıtı göndermeyi yalnızca belirli bir etkinlik için sendResponse()
işlevini ilk çağıran sayfa başarabilir. Etkinliğe verilen diğer tüm yanıtlar yoksayılır.
Uzun süreli bağlantılar
Yeniden kullanılabilir, uzun ömürlü bir mesajlaşma kanalı oluşturmak için şunu çağırın:
- İçerik komut dosyasından uzantı sayfasına mesaj iletmek için
runtime.connect()
tabs.connect()
: Uzantı sayfasından içerik komut dosyasına mesaj iletmek için kullanılır.
Farklı bağlantı türlerini ayırt etmek için name
anahtarıyla bir seçenek parametresi ileterek kanalınızı adlandırabilirsiniz:
const port = chrome.runtime.connect({name: "example"});
Uzun süreli bağlantıların olası kullanım alanlarından biri, otomatik form doldurma uzantısıdır. İçerik komut dosyası, belirli bir giriş için uzantı sayfasına bir kanal açabilir ve sayfadaki her giriş öğesi için uzantıya bir mesaj göndererek doldurulacak form verilerini isteyebilir. Paylaşılan bağlantı, uzantının uzantı bileşenleri arasında durumu paylaşmasına olanak tanır.
Bağlantı oluşturulurken her uca, bu bağlantı üzerinden mesaj göndermek ve almak için bir runtime.Port
nesnesi atanır.
İçerik komut dosyasından kanal açmak, mesaj göndermek ve mesaj dinlemek için aşağıdaki kodu kullanın:
content-script.js:
const port = chrome.runtime.connect({name: "knockknock"});
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"});
}
});
port.postMessage({joke: "Knock knock"});
Uzantıdan içerik komut dosyasına istek göndermek için önceki örnekteki runtime.connect()
çağrısını tabs.connect()
ile değiştirin.
İçerik komut dosyası veya uzantı sayfası için gelen bağlantıları işlemek üzere runtime.onConnect
etkinlik işleyicisini ayarlayın. Uzantınızın başka bir bölümü connect()
işlevini çağırdığında bu etkinlik ve runtime.Port
nesnesi etkinleştirilir. Gelen bağlantılara yanıt verme kodu şu şekilde görünür:
service-worker.js:
chrome.runtime.onConnect.addListener(function(port) {
if (port.name !== "knockknock") {
return;
}
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."});
}
});
});
Serileştirme
Chrome'da mesaj iletme API'leri JSON serileştirmeyi kullanır. Bu, bir mesajın (ve alıcılar tarafından sağlanan yanıtların) geçerli herhangi bir JSON değeri (null, boole, sayı, dize, dizi veya nesne) içerebileceği anlamına gelir. Diğer değerler, serileştirilebilir değerlere dönüştürülür.
Bu, aynı API'leri yapılandırılmış klon algoritmasıyla uygulayan diğer tarayıcılardan farklıdır.
Bağlantı noktası ömrü
Bağlantı noktaları, bir uzantının farklı bölümleri arasında iki yönlü iletişim mekanizması olarak tasarlanmıştır. Bir uzantının parçası tabs.connect()
, runtime.connect()
veya runtime.connectNative()
çağrıldığında, postMessage()
kullanarak mesajları anında gönderebilen bir Port oluşturur.
Bir sekmede birden fazla çerçeve varsa tabs.connect()
çağrıldığında sekmedeki her çerçeve için runtime.onConnect
etkinliği bir kez tetiklenir. Benzer şekilde, runtime.connect()
çağrılırsa onConnect
etkinliği, uzantı sürecindeki her kare için bir kez tetiklenebilir.
Örneğin, her açık bağlantı noktası için ayrı durumlar tutuyorsanız bir bağlantının ne zaman kapatıldığını öğrenmek isteyebilirsiniz. Bunu yapmak için runtime.Port.onDisconnect
etkinliğini dinleyin. Bu etkinlik, kanalın diğer ucunda geçerli bağlantı noktası olmadığında tetiklenir. Bunun nedenleri şunlar olabilir:
- Diğer tarafta
runtime.onConnect
dinleyicisi yok. - Bağlantı noktasını içeren sekmenin yüklemesi kaldırılır (örneğin, sekmede gezinme işlemi yapılıyorsa).
connect()
öğesinin çağrıldığı çerçeve kaldırıldı.- Bağlantı noktasını (
runtime.onConnect
üzerinden) alan tüm çerçeveler kaldırıldı. runtime.Port.disconnect()
, karşı taraf tarafından aranıyor. Birconnect()
araması, alıcının tarafında birden fazla bağlantı noktasıyla sonuçlanırsa ve bu bağlantı noktalarından herhangi birindedisconnect()
aranırsaonDisconnect
etkinliği yalnızca gönderen bağlantı noktasında tetiklenir, diğer bağlantı noktalarında tetiklenmez.
Uzantılar arası mesajlaşma
Uzantınızdaki farklı bileşenler arasında mesaj göndermenin yanı sıra, diğer uzantılarla iletişim kurmak için Messaging API'yi de kullanabilirsiniz. Bu sayede, diğer uzantıların kullanabileceği herkese açık bir API oluşturabilirsiniz.
Diğer uzantılardan gelen istekleri ve bağlantıları dinlemek için runtime.onMessageExternal
veya runtime.onConnectExternal
yöntemlerini kullanın. Her biriyle ilgili bir örneği aşağıda görebilirsiniz:
service-worker.js
// For a single request:
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.id !== allowlistedExtension) {
return; // don't allow this extension access
}
if (request.getTargetData) {
sendResponse({ targetData: targetData });
} else if (request.activateLasers) {
const 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.
});
});
Başka bir uzantıya mesaj göndermek için iletişim kurmak istediğiniz uzantının kimliğini aşağıdaki gibi iletin:
service-worker.js
// The ID of the extension we want to talk to.
const laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";
// For a minimal request:
chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
function(response) {
if (targetInRange(response.targetData))
chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
}
);
// For a long-lived connection:
const port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);
Web sayfalarından mesaj gönderme
Uzantılar, web sayfalarından gelen mesajları da alıp yanıtlayabilir. Bir web sayfasından uzantıya mesaj göndermek için manifest.json
dosyanızda "externally_connectable"
manifest anahtarını kullanarak hangi web sitelerinden mesajlara izin vermek istediğinizi belirtin. Örneğin:
manifest.json
"externally_connectable": {
"matches": ["https://*.example.com/*"]
}
Bu, mesajlaşma API'sini belirttiğiniz URL kalıplarıyla eşleşen tüm sayfalara sunar. URL kalıbı en az bir ikinci düzey alan içermelidir. Diğer bir deyişle, "*", "*.com", "*.co.uk" ve "*.appspot.com" gibi ana makine adı kalıpları desteklenmez. Tüm alanlara erişmek için <all_urls>
kullanabilirsiniz.
Belirli bir uzantıya mesaj göndermek için runtime.sendMessage()
veya runtime.connect()
API'lerini kullanın. Örneğin:
webpage.js
// The ID of the extension we want to talk to.
const editorExtensionId = 'abcdefghijklmnoabcdefhijklmnoabc';
// Check if extension is installed
if (chrome && chrome.runtime) {
// Make a request:
chrome.runtime.sendMessage(
editorExtensionId,
{
openUrlInEditor: url
},
(response) => {
if (!response.success) handleError(url);
}
);
}
Uzantınızdan, runtime.onMessageExternal
veya runtime.onConnectExternal
API'lerini kullanarak web sayfalarından gelen mesajları uzantılar arası mesajlaşmada olduğu gibi dinleyin. Aşağıda bununla ilgili bir örnek verilmiştir:
service-worker.js
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);
});
Bir uzantıdan bir web sayfasına mesaj gönderilemez.
Yerel mesajlaşma
Uzantılar, mesaj alışverişi yapabilir. Yerel mesajlaşma ana makinesi olarak kaydedilen yerel uygulamalarla. 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
Mesajlaşmayla ilgili birkaç güvenlik hususunu aşağıda bulabilirsiniz.
İçerik komut dosyaları daha az güvenilirdir
İçerik komut dosyaları, uzantı hizmeti çalışanına kıyasla daha az güvenilirdir. Örneğin, kötü amaçlı bir web sayfası, içerik komut dosyalarını çalıştıran oluşturma sürecini tehlikeye atabilir. İçerik komut dosyasından gelen iletilerin saldırgan tarafından oluşturulmuş olabileceğini varsayın ve tüm girişleri doğrulayıp temizlediğinizden emin olun. İçerik komut dosyasına gönderilen tüm verilerin web sayfasına sızabileceğini varsayın. İçerik komut dosyalarından alınan mesajlarla tetiklenebilecek ayrıcalıklı işlemlerin kapsamını sınırlayın.
Siteler arası komut dosyası çalıştırma
Komut dosyalarınızı siteler arası komut dosyası çalıştırmaya karşı koruduğunuzdan emin olun. Kullanıcı girişi, içerik komut dosyası aracılığıyla diğer web siteleri veya API gibi güvenilmeyen bir kaynaktan veri alırken bunu HTML olarak yorumlamaktan veya beklenmedik kodların çalışmasına izin verebilecek şekilde kullanmaktan kaçının.
Mümkün olduğunda komut dosyası çalıştırmayan API'leri kullanın:
service-worker.js
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // JSON.parse doesn't evaluate the attacker's scripts. const resp = JSON.parse(response.farewell); });
service-worker.js
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // innerText does not let the attacker inject HTML elements. document.getElementById("resp").innerText = response.farewell; });
Aşağıdaki yöntemleri kullanarak uzantınızın güvenlik açığına sahip olmasına neden olmayın:
service-worker.js
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // WARNING! Might be evaluating a malicious script! const resp = eval(`(${response.farewell})`); });
service-worker.js
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // WARNING! Might be injecting a malicious script! document.getElementById("resp").innerHTML = response.farewell; });