İçerik komut dosyaları, bunları çalıştıran uzantının değil, bir web sayfasının bağlamında çalıştığından, genellikle uzantının geri kalanıyla iletişim kurmanın yollarına ihtiyaç duyar. Ö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, ardından hizmet çalışanına söz konusu sayfa için bir işlem simgesi görüntülemesini bildirebilir.
Bu iletişimde mesaj aktarımı kullanılır. Bu sayede hem uzantılar hem de içerik komut dosyaları birbirlerinin mesajlarını dinleyebilir ve aynı kanalda yanıt verebilir. Bir mesaj, geçerli herhangi bir JSON nesnesi (boş, boole, sayı, dize, dizi veya nesne) içerebilir. İki mesaj aktarma API'si vardır: Tek seferlik istekler için bir API ve birden fazla mesajın gönderilmesine izin veren uzun süreli bağlantılar için daha karmaşık bir API. 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()
numaralı telefonu arayın.
Bu yöntemler, bir içerik komut dosyasından uzantıya veya uzantıdan bir içerik komut dosyasına tek seferlik JSON dizili mesaj göndermenize olanak tanır. Yanıtı işlemek için döndürülen sözü kullanın. Eski uzantılarla geriye dönük uyumluluk için son bağımsız değişken olarak geri çağırma işlevi gönderebilirsiniz. Aynı görüşmede hem söz hem de geri arama kullanamazsınız.
Geri çağırmaları vaatlere dönüştürme ve bunları uzantılarda kullanma hakkında bilgi için Manifest V3 taşıma rehberini inceleyin.
İç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);
})();
Bir mesajı senkronize olarak yanıtlamak istiyorsanız yanıtı aldıktan sonra sendResponse
işlevini çağırmanız ve işlemin tamamlandığını belirtmek için false
döndürmeniz yeterlidir. Asynkron yanıt vermek için true
döndürerek sendResponse
geri çağırma işlevini kullanmaya hazır olana kadar etkin tutun. Desteklenmeyen işlevler, desteklenmeyen bir Promise döndürdükleri için desteklenmiyor.
Bir içerik komut dosyasına istek göndermek için isteğin hangi sekme için geçerli olduğunu aşağıdaki gibi belirtin. Bu örnek, hizmet çalışanları, pop-up'lar ve sekme olarak açılan chrome-extension:// sayfalarında çalışır.
(async () => {
const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
const response = await chrome.tabs.sendMessage(tab.id, {greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();
Mesajı almak için bir runtime.onMessage
etkinlik işleyici ayarlayın. Aşağıdakiler hem uzantılarda hem de içerik komut dosyalarında aynı kodu kullanır:
content-script.js veya service-worker.js:
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"});
}
);
Önceki örnekte sendResponse()
zaman uyumlu olarak çağrılmıştır. sendResponse()
öğesini eşzamansız olarak kullanmak için onMessage
etkinlik işleyiciye return true;
ekleyin.
Birden fazla sayfa onMessage
etkinliklerini dinliyorsa yalnızca belirli bir etkinlik için sendResponse()
çağrısını ilk yapan sayfa yanıtı göndermeyi başarır. Bu etkinliğe verilen diğer tüm yanıtlar yoksayılır.
Uzun ömürlü bağlantılar
Yeniden kullanılabilir, uzun ömürlü bir mesaj iletme kanalı oluşturmak için mesajları içerik komut dosyasından bir uzantı sayfasına iletmek için runtime.connect()
veya bir uzantı sayfasından içerik komut dosyasına mesaj iletmek için tabs.connect()
çağrısı yapın. Farklı bağlantı türlerini ayırt etmek için kanalınızı adlandırabilirsiniz.
Uzun süreli bağlantını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 durum paylaşmasına olanak tanır.
Bağlantı kurulurken her uç noktaya, bu bağlantı üzerinden mesaj göndermek ve almak için bir runtime.Port
nesnesi atanır.
İçerik komut dosyasından bir kanal açmak, mesaj göndermek ve dinlemek için aşağıdaki kodu kullanın:
content-script.js:
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 bir içerik komut dosyasına istek göndermek için önceki örnekteki runtime.connect()
çağrısını tabs.connect()
ile değiştirin.
Bir içerik komut dosyası veya uzantı sayfası için gelen bağlantıları işlemek üzere bir runtime.onConnect
etkinlik işleyicisi ayarlayın. Uzantınızın başka bir bölümü connect()
'ü ç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) {
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. Üst düzey çerçeve, bir uzantının bağlantı noktasını kullanabilen en küçük kısmıdır.
Bir uzantının bir kısmı tabs.connect()
, runtime.connect()
veya runtime.connectNative()
'i çağrdığında postMessage()
kullanarak anında mesaj gönderebilen bir Port oluşturur.
Bir sekmede birden fazla çerçeve varsa tabs.connect()
çağrısı, sekmedeki her çerçeve için runtime.onConnect
etkinliğini bir kez tetikler. 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. Bu durum aşağıdakilerden herhangi birinden kaynaklanabilir:
- Diğer tarafta
runtime.onConnect
için dinleyici yok. - Bağlantı noktasını içeren sekme kaldırılır (örneğin, sekmeye gidilirse).
connect()
işlevinin çağrıldığı çerçeve kaldırıldı.- Bağlantı noktasını alan tüm çerçeveler kaldırıldı (
runtime.onConnect
üzerinden). runtime.Port.disconnect()
, karşı taraf tarafından aranır.connect()
çağrısı, alıcının ucunda birden fazla bağlantı noktasıyla sonuçlanırsa vedisconnect()
bu bağlantı noktalarından herhangi birinde çağrılırsaonDisconnect
etkinliği diğer bağlantı noktalarında değil, yalnızca gönderen bağlantı noktasında tetiklenir.
Çapraz uzantılar mesajlaşması
Mesajlaşma API'sini, uzantınızdaki farklı bileşenler arasında mesaj göndermenin yanı sıra diğer uzantılarla iletişim kurmak için de kullanabilirsiniz. Bu sayede, diğer uzantıların kullanabileceği herkese açık bir API sunabilirsiniz.
Diğer uzantılardan gelen isteklerini ve bağlantılarını dinlemek için runtime.onMessageExternal
veya runtime.onConnectExternal
yöntemlerini kullanın. Her biri için bir örnek aşağıda verilmiştir:
service-worker.js
// For a single request:
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.
});
});
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.
var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";
// For a simple request:
chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
function(response) {
if (targetInRange(response.targetData))
chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
}
);
// For a long-lived connection:
var port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);
Web sayfalarından mesaj gönderme
Uzantılar, diğer web sayfalarından gelen mesajları da alıp yanıtlayabilir ancak web sayfalarına mesaj gönderemez. Bir web sayfasından uzantıya mesaj göndermek için manifest.json
dosyanızda "externally_connectable"
manifest anahtarını kullanarak hangi web siteleriyle iletişim kurmak istediğinizi belirtin. Örneğin:
manifest.json
"externally_connectable": {
"matches": ["https://*.example.com/*"]
}
Bu işlem, Mesajlaşma API'sini belirttiğiniz URL kalıplarıyla eşleşen tüm sayfalara gösterir. URL kalıbı en az bir ikinci düzey alan içermelidir. Yani "*", "*.com", "*.co.uk" ve "*.appspot.com" gibi ana makine adı kalıpları desteklenmez. Chrome 107'den itibaren tüm alanlara erişmek için <all_urls>
kullanabilirsiniz. Tüm ana makineleri etkilediği için bu özelliği kullanan uzantıların Chrome Web Mağazası incelemelerinin daha uzun sürebileceğini unutmayın.
Belirli bir uygulama veya uzantıya mesaj göndermek için runtime.sendMessage()
ya da runtime.connect()
API'lerini kullanın. Örneğin:
webpage.js
// 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);
});
Uzantıdan, uzantılar arası mesajlaşmada olduğu gibi runtime.onMessageExternal
veya runtime.onConnectExternal
API'lerini kullanarak web sayfalarından gelen mesajları dinleyebilirsiniz. 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);
});
Yerel mesajlaşma
Uzantılar, yerel mesajlaşma sunucusu olarak kayıtlı yerel uygulamalarla mesaj alışverişi yapabilir. Bu özellik hakkında daha fazla bilgi edinmek için Yerel mesajlaşma bölümüne bakın.
Güvenlikle ilgili olarak göz önünde bulundurulması gerekenler
Mesajlaşmayla ilgili güvenlikle ilgili birkaç noktayı aşağıda bulabilirsiniz.
İçerik komut dosyaları daha az güvenilirdir.
İçerik komut dosyaları, uzantı hizmet işçisine 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 mesajların bir saldırgan tarafından hazırlanmış olabileceğini varsayarak tüm girişleri doğruladığınızdan ve temizlediğinizden emin olun. İçerik komut dosyasına gönderilen tüm verilerin web sayfasına sızdırılabileceğ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ırma işlemlerine karşı koruduğunuzdan emin olun. Kullanıcı girişi, içerik komut dosyası veya API aracılığıyla diğer web siteleri gibi güvenilmeyen bir kaynaktan veri alırken bu verileri HTML olarak yorumlamaktan veya beklenmedik kodun çalıştırılmasına izin verebilecek bir şekilde kullanmaktan kaçının.
Mümkün olduğunda komut dosyalarını çalıştırmayan API'ler kullanın:
service-worker.js
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // JSON.parse doesn't evaluate the attacker's scripts. var 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; });
Uzantılarınızın güvenliğini ihlal eden aşağıdaki yöntemleri kullanmaktan kaçının:
service-worker.js
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // WARNING! Might be evaluating a malicious script! var 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; });