Content Scriptsでのクロスドメイン通信
Contents Scripsとクロスドメイン通信
ChromeのExtentionの実装方法の一つに、Content Scriptsというものがあります。一言で言えば、FirefoxのGreasemonkeyのChrome版です。Content Scriptsを使用すると、任意のWebページに対して、JavaScriptを実行することができます。これにより、本来Webページにはない機能をWebページに追加することができます。
ChromeのExtentionでは、普通のWebページ内のJavascriptとは違い、クロスドメイン通信が可能です。
BackgroudPagesやポップアップなどからクロスドメイン通信をする場合は、XMLHttpRequestなり、jQueryやprototypeなどで用意されているHttpRequest用のオブジェクトを使用すれば可能です。
一方、Contents Scriptsから直接クロスドメイン通信をすることはできません。しかし、BackgroundPagesを用意し、通信自体はBackgroudPagesに行わせるという回りくどい方法で実現可能です。
具体的には、Content Scriptsからchrome.extention.sendRequestという関数を呼び出し、httpリクエストのパラーメータとレスポンスを処理するコールバックをBackgroundPagesに送ります。その後、BackgroundPagesは
クロスドメイン通信を行い、そのレスポンスをContentScriptsから受け取ったコールバックに渡して呼び出します。この一連の流れを下に図示しておきます。
ContentScriptsによるクロスドメイン通信概要図
以下では、Google検索時にYahooによる検索も同時に行い、Googleの広告が表示される部分にYahooの検索結果を埋め込むという簡単なExtentionを例に、Contents Scriptsからのクロスドメイン通信を説明してみます。
サンプルのソースコード
(ソースコード中のYahoo検索 APIを利用するためのアプリケーションIDを記述している箇所を変更しなければ動きません)
Content Scriptsによるクロスドメイン通信のサンプルExtention
manifest.json
1 { 2 "name": "Double Search", 3 "version": "1.0", 4 "description": "Double Search", 5 "background_page": "background.html", 6 "content_scripts": [ 7 { 8 "matches": ["http://www.google.co.jp/search*", "http://www.google.co.jp/search*"], 9 "js": ["prototype.js", "contentscript.js"], 10 "run_at" : "document_end" 11 } 12 ], 13 "permissions": [ 14 "http://search.yahooapis.jp/WebSearchService/V1/webSearch*" 15 ] 16 }
5行目でクロスドメイン通信を行うBackgroundPagesとして「background.html」を指定しています。
6行目から12行目がContentScriptsを設定する上で重要な箇所です。7行目のmatchesでContentScriptsを動作させるサイトを指定しています。8行目で使用するJavascriptファイルを指定しています。ここで記述した順番にロードされます。contentscript.jsではJavascriptライブラリのprototype.jsを利用するので、contentscript.jsより先にprototype.jsを記述しておきます。9行目では動作タイミングを指定しています。
13行目から15行目でクロスドメイン通信を行うサイトのURL(この例では、Yahoo検索 APIのURL)を指定しています。
contentscript.js(重要部分のみ)
13 function searchByYahoo() { 14 var query = getQuery(); 15 16 chrome.extension.sendRequest(query, function(res) { 17 console.log("get response"); 18 console.log(res); 省略 30 }); 31 }
14行目で、Google検索の検索結果ページからクエリを取得しています。
16行目では、chrome.extention.sendRequestを呼び出すことで、BackgroundPages(この例では「background.html」)へYahoo検索に使用するクエリと、Yahooの検索結果を処理するコールバックを渡しています。
background.html
1 <html> 2 <head> 3 <script type="text/javascript" src="prototype.js"></script> 4 <script> 5 chrome.extension.onRequest.addListener(function(request, sender, sendResponse) { 6 console.log(sender.tab ? "from a content script:" + sender.tab.url : "from the extension"); 7 8 new Ajax.Request("http://search.yahooapis.jp/WebSearchService/V1/webSearch", { 9 method : "get", 10 parameters : {"query" : request, "appid" : "appid"}, 11 onSuccess : function(res) { 12 sendResponse(res.responseText); 13 }, 14 onFailure : function(res) { 15 sendResponse(null); 16 } 17 }); 18 }); 19 </script> 20 </head> 21 <body></body> 22 </html>
ここで一番重要なのは、5行目で呼び出している関数chrome.extention.onRequest.addListenerです。この関数では、ContentScriptsからsendRequestを呼び出したときに呼び出すコールバックが引数となります。このコールバックの第一引数requestは、ContentScriptsから送られてきたメッセージ(chrome.extention.sendRequestの第一引数)、第3引数sendResponseは返信を処理するコールバック(chrome.extention.sendRequestの第三引数)となります。
8から17行目で、実際にクロスドメイン通信を行っています。12行目で、sendResponseを呼び出して、クロスドメイン通信の相手サイトからのレスポンスの内容をContentScriptsへ送っています。ここではレスポンスのオブジェクトそのものではなく、テキストレスポンスを渡しています。これは、sendResponseには、JSONオブジェクトかundefiedしか引数として渡せないためです。もし、XMLレスポンスなどを渡すとsendResponseは動作しません。ここで、私は1時間くらいはまりました)。
最後に
特になし