मैसेज पास करना

कॉन्टेंट स्क्रिप्ट, एक्सटेंशन के बजाय वेब पेज के हिसाब से काम करती हैं. इसलिए, उन्हें एक्सटेंशन के साथ इंटरैक्ट करने के लिए किसी न किसी तरीके की ज़रूरत पड़ती है. उदाहरण के लिए, कोई आरएसएस रीडर एक्सटेंशन किसी पेज पर आरएसएस फ़ीड होने का पता लगाने के लिए, कॉन्टेंट स्क्रिप्ट का इस्तेमाल कर सकता है. इसके बाद, बैकग्राउंड पेज को सूचना देकर उस पेज पर कार्रवाई करने का आइकॉन दिखा सकता है.

एक्सटेंशन और उनकी कॉन्टेंट स्क्रिप्ट के बीच कम्यूनिकेशन, मैसेज पासिंग का इस्तेमाल करके काम करता है. दोनों तरफ़ से भेजे गए मैसेज, दोनों तरफ़ से सुने जा सकते हैं और उसी चैनल से जवाब भी दिए जा सकते हैं. मैसेज में कोई भी मान्य 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; जोड़ें.

ध्यान दें: अगर एक से ज़्यादा पेज onMessage इवेंट सुन रहे हैं, तो किसी खास इवेंट के लिए sendResponse() को सबसे पहले कॉल करने वाला व्यक्ति ही जवाब भेज पाएगा. उस इवेंट के अन्य सभी जवाबों को अनदेखा कर दिया जाएगा.
ध्यान दें: sendResponse कॉलबैक सिर्फ़ तब मान्य होता है, जब इसे सिंक्रोनस रूप से इस्तेमाल किया जाता है या अगर इवेंट हैंडलर true दिखाता है, तो यह बताता है कि वह एसिंक्रोनस तरीके से जवाब देगा. अगर कोई भी हैंडलर 'सही' नहीं दिखाता है या sendResponse कॉलबैक गार्बेज-कलेक्ट किया जाता है, तो sendMessage फ़ंक्शन का कॉलबैक अपने-आप शुरू हो जाएगा.

लंबे समय तक चले कनेक्शन

कभी-कभी ऐसी बातचीत करना ज़्यादा अच्छा होता है जो एक अनुरोध और जवाब से ज़्यादा देर तक चलती हो. इस मामले में, कॉन्टेंट स्क्रिप्ट से एक्सटेंशन पेज पर लंबे समय तक चलने वाला चैनल खोला जा सकता है. इसके अलावा, 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 को कॉल करने पर, एक पोर्ट बनाया जाता है. यह पोर्ट 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 ऐप्लिकेशन, किसी नेटिव ऐप्लिकेशन से कैसे इंटरैक्ट कर सकता है. ज़्यादा उदाहरण देखने और सोर्स कोड को देखने में मदद पाने के लिए, सैंपल देखें.