# 消息傳遞
## 目錄
1. [一次簡單的請求](#simple)
1. <a>h3Name</a>
2. [長時間保持連接](#connect)
1. <a>h3Name</a>
3. [擴展之間的消息傳遞](#external)
1. <a>h3Name</a>
4. [安全策略](#security-considerations)
1. <a>h3Name</a>
5. [范例](#examples)
1. <a>h3Name</a>
6. [API reference](#apiReference)
1. [Properties](#properties)
1. [propertyName](#property-anchor)
2. [Methods](#methods)
1. [methodName](#method-anchor)
3. [Events](#events)
1. [eventName](#event-anchor)
4. [Types](#types)
1. [id](#id-anchor)
For information on how to use experimental APIs, see the [chrome.experimental.* APIs](experimental.html) page.
消息傳遞自從content script內容運行在網頁環境而不是在擴展中,我們經常需要一些方法和其余的擴展進行通信。例如,一個 RSS閱讀擴展可能會使用content scripts去檢測RSS閱讀擴展應該提供給哪個頁面,然后通知后臺頁面以便顯示一個頁面交互圖標。
通過使用消息傳遞機制在擴展和content scripts中通信,任何一方可以收到另一方傳遞來的消息,并且在相同的通道上答復。這個消息可以包含 任何一個有效的JSON對象(null, boolean, number, string, array, or object)。這里有一些簡單的API對于 [一次簡單的請求](#simple),還有更多復雜的API,它們可以幫助你[長時間保持連接](#connect)在一個共享的環境中交換大量的信息,它也可以幫助你傳遞消息給另外一個你知道ID的擴展 ,在[擴展之間的消息傳遞](#external)這里會有詳細的講解。
## 一次簡單的請求
如果你僅僅需要給你自己的擴展的另外一部分發送一個消息(可選的是否得到答復),你可以簡單地使用[chrome.extension.sendRequest()](extension.html#method-sendRequest)或者[chrome.tabs.sendRequest()](tabs.html#method-sendRequest)方法。這個方法可以幫助你傳送一次JSON序列化消息從content script到擴展,反之亦然。如果接受消息的一方存在的話,可選的回調參數允許處理傳回來的消息。
像下面這個例子一樣,可以從content script 發起一個請求:
```
contentscript.js
================
chrome.extension.sendRequest({greeting: "hello"}, function(response) {
console.log(response.farewell);
});
```
傳遞一個請求到擴展很容易,你需要指定哪個標簽發起這個請求。下面這個例子展示了如何指定標簽發起一個請求。
```
background.html
===============
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
```
接受消息的一方,需要啟動一個[chrome.extension.onRequest](extension.html#event-onRequest)事件監聽器用來處理消息。這個方法在content script和擴展中都是一樣的。這個請求將會保留直到你做出了回應。下面的這個例子是一個很好的做法調用一個空對象請求然后得到答復的例子。
```
chrome.extension.onRequest.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"});
else
sendResponse({}); // snub them.
});
```
**小提示:**如果多個頁面都發起了相同的請求,都在等待答復,只有第一個發起請求的頁面會得到響應,其他的將會被忽略。
## 長時間的保持連接
有時候持續長時間的保持會話會比一次簡單的請求有用。你可以建立一個長時間存在的通道從content script到擴展, 反之亦然,使用[chrome.extension.connect()](extension.html#method-connect)或者[chrome.tabs.connect()](tabs.html#method-connect)方法,你可以把這個通道命名,為了更方便區分不同類型的連接。
一個有用的例子就是自動填寫表單擴展。content script可以建立一個通道在登錄頁面和擴展之間,同時發出一條消息給擴展,告訴擴展需要填寫的內容。共享的連接允許擴展保持共享狀態,從而連接幾個來自content script.的消息。
當建立連接,兩端都有一個[Port](extension.html#type-Port) 對象通過這個連接發送和接收消息。
下面展示了如何從content script建立一個通道,發送和接受消息:
```
contentscript.js
================
var port = chrome.extension.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"});
});
```
從擴展到content script發送一個請求看起來非常簡單,除了你需要指定哪個標簽需要連接, 簡單的辦法就是上面例子中的[chrome.tabs.connect(tabId, {name: "knockknock"})](tabs.html#method-connect).
為了處理正在等待的連接,你需要用[chrome.extension.onConnect](extension.html#event-onConnect) 事件監聽器,對于content script或者擴展頁面,這個方法都是一樣的,但你的擴展的另外一個部分調用"connect()", 這個事件一旦被觸發,通過這個連接你可以利用[Port](extension.html#type-Port)對象進行發送和接收消息,下面的例子展示了如何處理連接:
```
chrome.extension.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."});
});
});
```
你可能想知道這個連接什么時候被關閉。例如,如果你在為每個開放的端口維護分開的狀態,如果你想知道它什么時候關閉,因此,需要監聽[Port.onDisconnect](extension.html#type-Port) 事件,這個事件被激發,要么是通道調用了[Port.disconnect()](extension.html#type-Port)這個方法,要么這個頁面包含的端口沒有被加載(例如這個標簽是個導航欄) ,onDisconnect()保證僅僅被激發一次。
## 擴展之間的消息傳遞
除了在擴展的組件之間傳送消息,你還可以使用消息API來和其他的擴展之間進行通信,你可以使用一個其他擴展也可以利用的公共API。
對于擴展內部來說,監聽一個傳入的請求和連接是一樣的,你可以使用[chrome.extension.onRequestExternal](extension.html#event-onRequestExternal)或者[chrome.extension.onConnectExternal](extension.html#event-onConnectExternal)方法,如下面的例子所示:
```
// For simple requests:
chrome.extension.onRequestExternal.addListener(
function(request, sender, sendResponse) {
if (sender.id == blacklistedExtension)
sendResponse({}); // 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.extension.onConnectExternal.addListener(function(port) {
port.onMessage.addListener(function(msg) {
// See other examples for sample onMessage handlers.
});
});
```
同樣,傳遞一個消息到另外一個擴展和把消息傳遞給自己擴展的另外一部分是一樣的,唯一不同的是你必須知道你要傳給消息的擴展的ID例如:
```
// The ID of the extension we want to talk to.
var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";
// Make a simple request:
chrome.extension.sendRequest(laserExtensionId, {getTargetData: true},
function(response) {
if (targetInRange(response.targetData))
chrome.extension.sendRequest(laserExtensionId, {activateLasers: true});
});
// Start a long-running conversation:
var port = chrome.extension.connect(laserExtensionId);
port.postMessage(...);
```
## 安全策略
無論是從content script還是從擴展接收消息,你的頁面不應該[cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting),特別是避免使用那些不安全的API例如下面的例子:
```
background.html
===============
chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
// WARNING! Might be evaluating an evil script!
var resp = eval("(" + response.farewell + ")");
});
background.html
===============
chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
// WARNING! Might be injecting a malicious script!
document.getElementById("resp").innerHTML = response.farewell;
});
```
相反的,選擇更安全的API而不是運行腳本。
```
background.html
===============
chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
// JSON.parse does not evaluate the attacker's scripts.
var resp = JSON.parse(response.farewell);
});
background.html
===============
chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
// innerText does not let the attacker inject HTML elements.
document.getElementById("resp").innerText = response.farewell;
});
```
## 范例
你可以在這個[examples/api/messaging](http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/messaging/) 目錄下找到消息傳遞的例子,也可以找到[contentscript_xhr](http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/howto/contentscript_xhr) (contents script和擴展之間傳遞消息的例子),更多的內容和源碼,請查看[Smples](samples.html).
## API reference: chrome.apiname
### Properties
<a></a>
#### getLastError
chrome.extensionlastError
### Methods
<a></a>
#### method name
void chrome.module.methodName(, ``)
Undocumented.
A description from the json schema def of the function goes here.
#### Parameters
#### Returns
#### Callback function
The callback _parameter_ should specify a function that looks like this:
If you specify the _callback_ parameter, it should specify a function that looks like this:
```
function(Type param1, Type param2) {...};
```
This function was added in version . If you require this function, the manifest key [minimum_chrome_version](manifest.html#minimum_chrome_version) can ensure that your extension won't be run in an earlier browser version.
### Events
<a></a>
#### event name
chrome.bookmarksonEvent.addListener(function(Type param1, Type param2) {...});
Undocumented.
A description from the json schema def of the event goes here.
#### Parameters
### Types
<a></a>
#### type name
- 基礎文檔
- 綜述
- 調試
- 格式:Manifest文件
- 模式匹配
- 改變瀏覽器外觀
- Browser Actions
- Context Menus
- 桌面通知
- Omnibox
- Override替代頁
- Page Actions
- 主題
- 與瀏覽器交互
- 書簽
- Cookies
- chrome.devtools.* APIs
- Events
- chrome.history
- Management
- 標簽
- 視窗
- 實現擴展
- 無障礙性(a11y)
- 背景頁
- Content Scripts
- 跨域 XMLHttpRequest 請求
- 國際化 (i18n)
- 消息傳遞
- Optional Permissions
- NPAPI 插件
- 完成并發布應用
- 自動升級
- 托管
- 打包
- 規范和協議
- 應用設計規范
- 開發人員協議
- 免責聲明