कॉन्टेंट स्क्रिप्ट, एक्सटेंशन के बजाय वेब पेज के कॉन्टेक्स्ट में चलती हैं. इसलिए, इन्हें अक्सर एक्सटेंशन के बाकी हिस्सों से कम्यूनिकेट करने के लिए किसी तरीके की ज़रूरत होती है. उदाहरण के लिए, आरएसएस रीडर एक्सटेंशन, किसी पेज पर आरएसएस फ़ीड का पता लगाने के लिए कॉन्टेंट स्क्रिप्ट का इस्तेमाल कर सकता है. इसके बाद, वह बैकग्राउंड पेज को सूचना देता है, ताकि उस पेज के लिए पेज ऐक्शन आइकॉन दिखाया जा सके.
एक्सटेंशन और उनकी कॉन्टेंट स्क्रिप्ट के बीच कम्यूनिकेशन, मैसेज पास करने की सुविधा का इस्तेमाल करके काम करता है. दोनों में से कोई भी व्यक्ति, दूसरे व्यक्ति के भेजे गए मैसेज सुन सकता है और उसी चैनल पर जवाब दे सकता है. किसी मैसेज में कोई भी मान्य JSON ऑब्जेक्ट (शून्य, बूलियन, संख्या, स्ट्रिंग, ऐरे या ऑब्जेक्ट) हो सकता है. एक बार के अनुरोधों के लिए, एक आसान एपीआई उपलब्ध है. साथ ही, एक ज़्यादा जटिल एपीआई भी उपलब्ध है. इसकी मदद से, शेयर किए गए कॉन्टेक्स्ट के साथ कई मैसेज का आदान-प्रदान करने के लिए, लंबे समय तक चलने वाले कनेक्शन बनाए जा सकते हैं. अगर आपको किसी दूसरे एक्सटेंशन का आईडी पता है, तो उसे मैसेज भेजा जा सकता है. इसके बारे में एक से ज़्यादा एक्सटेंशन के बीच मैसेज भेजने की सुविधा सेक्शन में बताया गया है.
एक बार किए जाने वाले सामान्य अनुरोध
अगर आपको अपने एक्सटेंशन के किसी दूसरे हिस्से में सिर्फ़ एक मैसेज भेजना है और आपको जवाब भी चाहिए, तो आपको आसान runtime.sendMessage या tabs.sendMessage का इस्तेमाल करना चाहिए . इसकी मदद से, कॉन्टेंट स्क्रिप्ट से एक्सटेंशन को या एक्सटेंशन से कॉन्टेंट स्क्रिप्ट को एक बार भेजा जाने वाला JSON-सीरियलाइज़ किया जा सकने वाला मैसेज भेजा जा सकता है. ज़रूरी नहीं है कि कॉलबैक पैरामीटर का इस्तेमाल किया जाए. इससे आपको दूसरी ओर से मिले जवाब को मैनेज करने में मदद मिलती है.
कॉन्टेंट स्क्रिप्ट से अनुरोध भेजने का तरीका यहां दिखाया गया है:
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response.farewell);
});
एक्सटेंशन से किसी कॉन्टेंट स्क्रिप्ट को अनुरोध भेजने का तरीका भी काफ़ी हद तक एक जैसा होता है. हालांकि, इसमें आपको यह बताना होता है कि अनुरोध किस टैब को भेजना है. इस उदाहरण में, चुनी गई टैब में मौजूद कॉन्टेंट स्क्रिप्ट को मैसेज भेजने का तरीका दिखाया गया है.
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
मैसेज पाने वाले एक्सटेंशन में, मैसेज को हैंडल करने के लिए runtime.onMessage इवेंट लिसनर सेट अप करना होगा. यह कॉन्टेंट स्क्रिप्ट या एक्सटेंशन पेज से एक जैसा दिखता है.
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"});
}
);
ऊपर दिए गए उदाहरण में, sendResponse को सिंक्रोनस तरीके से कॉल किया गया था. अगर आपको sendResponse का इस्तेमाल एसिंक्रोनस तरीके से करना है, तो onMessage इवेंट हैंडलर में return true; जोड़ें.
sendResponse कॉलबैक सिर्फ़ तब मान्य होता है, जब इसका इस्तेमाल सिंक्रोनस तरीके से किया जाता है. इसके अलावा, यह तब भी मान्य होता है, जब इवेंट हैंडलर true दिखाता है, ताकि यह पता चल सके कि वह एसिंक्रोनस तरीके से जवाब देगा. अगर कोई हैंडलर 'सही' वैल्यू नहीं दिखाता है या sendMessage कॉलबैक को गार्बेज-कलेक्ट किया जाता है, तो sendMessage फ़ंक्शन का कॉलबैक अपने-आप शुरू हो जाएगा.sendResponseलंबे समय तक चलने वाले कनेक्शन
कभी-कभी, एक ही अनुरोध और जवाब के बजाय, लंबी बातचीत करना ज़्यादा फ़ायदेमंद होता है. इस मामले में, runtime.connect या tabs.connect का इस्तेमाल करके, अपनी कॉन्टेंट स्क्रिप्ट से एक्सटेंशन पेज पर या इसके उलट, लंबे समय तक चलने वाला चैनल खोला जा सकता है . चैनल का नाम भी रखा जा सकता है. इससे आपको अलग-अलग तरह के कनेक्शन के बीच अंतर करने में मदद मिलती है.
ऑटोमैटिक तरीके से फ़ॉर्म भरने वाला एक्सटेंशन, इसका एक उदाहरण हो सकता है. कॉन्टेंट स्क्रिप्ट, किसी खास लॉगिन के लिए एक्सटेंशन पेज पर एक चैनल खोल सकती है. साथ ही, पेज पर मौजूद हर इनपुट एलिमेंट के लिए एक्सटेंशन को एक मैसेज भेज सकती है. इससे, फ़ॉर्म में डेटा भरने का अनुरोध किया जा सकता है. शेयर किए गए कनेक्शन की मदद से एक्सटेंशन, शेयर की गई स्थिति को बनाए रख सकता है. इससे कॉन्टेंट स्क्रिप्ट से आने वाले कई मैसेज लिंक किए जा सकते हैं.
कनेक्शन बनाते समय, हर एंड को runtime.Port ऑब्जेक्ट दिया जाता है. इसका इस्तेमाल, उस कनेक्शन के ज़रिए मैसेज भेजने और पाने के लिए किया जाता है.
कॉन्टेंट स्क्रिप्ट से चैनल खोलने और मैसेज भेजने और सुनने का तरीका यहां बताया गया है:
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"});
});
एक्सटेंशन से कॉन्टेंट स्क्रिप्ट को अनुरोध भेजने का तरीका काफ़ी हद तक एक जैसा होता है. हालांकि, इसमें आपको यह बताना होता है कि किस टैब से कनेक्ट करना है. ऊपर दिए गए उदाहरण में, कनेक्ट करने के लिए कॉल करने के बजाय, tabs.connect का इस्तेमाल करें.
आने वाले कनेक्शन को मैनेज करने के लिए, आपको runtime.onConnect इवेंट लिसनर सेट अप करना होगा. कॉन्टेंट स्क्रिप्ट या एक्सटेंशन पेज से यह एक जैसा दिखता है. जब आपके एक्सटेंशन का कोई दूसरा हिस्सा "connect()" को कॉल करता है, तब यह इवेंट फ़ायर होता है. साथ ही, runtime.Port ऑब्जेक्ट भी फ़ायर होता है. इस ऑब्जेक्ट का इस्तेमाल, कनेक्शन के ज़रिए मैसेज भेजने और पाने के लिए किया जा सकता है. यहां बताया गया है कि आने वाले कनेक्शन का जवाब देने के लिए, यह कैसा दिखता है:
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."});
});
});
पोर्ट करने की अवधि
पोर्ट को एक्सटेंशन के अलग-अलग हिस्सों के बीच दो-तरफ़ा बातचीत करने के तरीके के तौर पर डिज़ाइन किया गया है. इसमें (टॉप-लेवल) फ़्रेम को सबसे छोटा हिस्सा माना जाता है. tabs.connect, runtime.connect या runtime.connectNative को कॉल करने पर, एक Port बनाया जाता है. इस पोर्ट का इस्तेमाल, postMessage के ज़रिए दूसरे एंड पर मैसेज भेजने के लिए तुरंत किया जा सकता है.
अगर किसी टैब में एक से ज़्यादा फ़्रेम हैं, तो tabs.connect को कॉल करने पर, runtime.onConnect इवेंट कई बार ट्रिगर होता है. ऐसा टैब में मौजूद हर फ़्रेम के लिए एक बार होता है. इसी तरह, अगर runtime.connect का इस्तेमाल किया जाता है, तो onConnect इवेंट को कई बार ट्रिगर किया जा सकता है. ऐसा एक्सटेंशन प्रोसेस में मौजूद हर फ़्रेम के लिए एक बार होता है.
आपको यह पता लगाना पड़ सकता है कि कनेक्शन कब बंद हुआ. उदाहरण के लिए, अगर आपको हर खुले पोर्ट के लिए अलग-अलग स्थिति बनाए रखनी है. इसके लिए, runtime.Port.onDisconnect इवेंट सुना जा सकता है. यह इवेंट तब ट्रिगर होता है, जब चैनल के दूसरे हिस्से में कोई मान्य पोर्ट नहीं होता. ऐसा इन स्थितियों में होता है:
- दूसरे डिवाइस पर, runtime.onConnect के लिए कोई लिसनर मौजूद नहीं है.
- पोर्ट वाला टैब अनलोड हो गया हो. जैसे, अगर टैब पर नेविगेट किया गया हो.
- जिस फ़्रेम से
connectको कॉल किया गया था वह अनलोड हो गया है. - runtime.onConnect के ज़रिए पोर्ट पाने वाले सभी फ़्रेम अनलोड हो गए हैं.
- runtime.Port.disconnect को दूसरे एंड से कॉल किया जाता है. ध्यान दें कि अगर
connectकॉल की वजह से, रिसीवर के एंड पर एक से ज़्यादा पोर्ट होते हैं और इनमें से किसी भी पोर्ट परdisconnect()कॉल किया जाता है, तोonDisconnectइवेंट सिर्फ़ भेजने वाले के पोर्ट पर ट्रिगर होता है, न कि अन्य पोर्ट पर.
एक से ज़्यादा एक्सटेंशन के बीच मैसेज भेजने की सुविधा
एक्सटेंशन के अलग-अलग कॉम्पोनेंट के बीच मैसेज भेजने के अलावा, अन्य एक्सटेंशन से कम्यूनिकेट करने के लिए मैसेजिंग एपीआई का इस्तेमाल किया जा सकता है. इससे आपको एक ऐसा सार्वजनिक एपीआई उपलब्ध कराने में मदद मिलती है जिसका फ़ायदा अन्य एक्सटेंशन ले सकते हैं.
आने वाले अनुरोधों और कनेक्शन के लिए लिसनिंग, इंटरनल केस की तरह ही होती है. हालांकि, इसमें runtime.onMessageExternal या runtime.onConnectExternal तरीकों का इस्तेमाल किया जाता है. यहां हर एक का उदाहरण दिया गया है:
// 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.
});
});
इसी तरह, किसी दूसरे एक्सटेंशन को मैसेज भेजना, अपने एक्सटेंशन में मैसेज भेजने जैसा ही होता है. इनमें सिर्फ़ यह अंतर है कि आपको उस एक्सटेंशन का आईडी पास करना होगा जिससे आपको कम्यूनिकेट करना है. उदाहरण के लिए:
// 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(...);
वेब पेजों से मैसेज भेजना
एक से ज़्यादा एक्सटेंशन के बीच मैसेज भेजने की सुविधा की तरह ही, आपका ऐप्लिकेशन या एक्सटेंशन सामान्य वेब पेजों से मैसेज पा सकता है और उनका जवाब दे सकता है. इस सुविधा का इस्तेमाल करने के लिए, आपको पहले manifest.json फ़ाइल में यह बताना होगा कि आपको किन वेबसाइटों से कम्यूनिकेट करना है. उदाहरण के लिए:
"externally_connectable": {
"matches": ["*://*.example.com/*"]
}
इससे मैसेजिंग एपीआई, उन सभी पेजों के लिए उपलब्ध हो जाएगा जो आपके बताए गए यूआरएल पैटर्न से मेल खाते हैं. यूआरएल पैटर्न में कम से कम एक सेकंड-लेवल डोमेन होना चाहिए. इसका मतलब है कि "*", "*.com", "*.co.uk", और "*.appspot.com" जैसे होस्टनेम पैटर्न इस्तेमाल नहीं किए जा सकते. वेब पेज से, runtime.sendMessage या runtime.connect एपीआई का इस्तेमाल करके, किसी खास ऐप्लिकेशन या एक्सटेंशन को मैसेज भेजें. उदाहरण के लिए:
// 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);
});
अपने ऐप्लिकेशन या एक्सटेंशन से, वेब पेजों के मैसेज सुने जा सकते हैं. इसके लिए, runtime.onMessageExternal या runtime.onConnectExternal एपीआई का इस्तेमाल किया जा सकता है. यह क्रॉस-एक्सटेंशन मैसेजिंग की तरह ही काम करता है. सिर्फ़ वेब पेज, कनेक्शन शुरू कर सकता है. उदाहरण के लिए:
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);
});
नेटिव मैसेज सेवा
एक्सटेंशन और ऐप्लिकेशन, मैसेज भेज और पा सकते हैं. इसके लिए, उन्हें नेटिव ऐप्लिकेशन के साथ रजिस्टर करना होगा. साथ ही, उन्हें नेटिव मैसेजिंग होस्ट के तौर पर रजिस्टर करना होगा. इस सुविधा के बारे में ज़्यादा जानने के लिए, नेटिव मैसेजिंग लेख पढ़ें.
सुरक्षा से जुड़ी बातें
कॉन्टेंट स्क्रिप्ट पर कम भरोसा किया जा सकता है
कॉन्टेंट स्क्रिप्ट, एक्सटेंशन के बैकग्राउंड पेज की तुलना में कम भरोसेमंद होती हैं.उदाहरण के लिए, नुकसान पहुंचाने वाला कोई वेब पेज, रेंडरर प्रोसेस को नुकसान पहुंचा सकता है. इसी प्रोसेस में कॉन्टेंट स्क्रिप्ट चलती हैं. मान लें कि कॉन्टेंट स्क्रिप्ट से मिले मैसेज, किसी हमलावर ने बनाए हैं. साथ ही, यह पक्का करें कि सभी इनपुट की पुष्टि की गई हो और उन्हें सुरक्षित किया गया हो. मान लें कि कॉन्टेंट स्क्रिप्ट को भेजा गया कोई भी डेटा, वेब पेज पर लीक हो सकता है. कॉन्टेंट स्क्रिप्ट से मिले मैसेज से ट्रिगर की जा सकने वाली खास कार्रवाइयों के स्कोप को सीमित करें.
क्रॉस-साइट स्क्रिप्टिंग
जब आपको किसी कॉन्टेंट स्क्रिप्ट या अन्य एक्सटेंशन से कोई मैसेज मिलता है, तो आपकी स्क्रिप्ट को यह ध्यान रखना चाहिए कि वह क्रॉस-साइट स्क्रिप्टिंग का शिकार न हो. यह सलाह, एक्सटेंशन के बैकग्राउंड पेज में चलने वाली स्क्रिप्ट के साथ-साथ, अन्य वेब ऑरिजिन में चलने वाली कॉन्टेंट स्क्रिप्ट पर भी लागू होती है. खास तौर पर, नुकसान पहुंचाने वाले एपीआई का इस्तेमाल न करें. जैसे, यहां दिए गए एपीआई:
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;
});
इसके बजाय, ऐसे सुरक्षित एपीआई का इस्तेमाल करें जो स्क्रिप्ट नहीं चलाते:
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;
});
उदाहरण
आपको examples/api/messaging डायरेक्ट्री में, मैसेज के ज़रिए बातचीत करने के आसान उदाहरण मिल सकते हैं. नेटिव मैसेजिंग के सैंपल से पता चलता है कि Chrome ऐप्लिकेशन, नेटिव ऐप्लिकेशन से कैसे कम्यूनिकेट कर सकता है. ज़्यादा उदाहरण देखने और सोर्स कोड देखने में मदद पाने के लिए, सैंपल देखें.