Cross-domain XMLHttpRequest using background pages
You don't have to mess with iframes. It's possible to perform cross-domain XMLHttpRequests, using background pages. Since Chrome 13, cross-site requests can be made from the content script. However, requests can still fail if the page is served with a Content Security Policy header with a restricting connect-src
.
Another reason for choosing the nexy method over content scripts is that requests to http sites will cause a mixed content warning ("The page at https://... displayed insecure content from http://...").
Yet another reason for delegating the request to the background page is when you want to get a resource from the file://
, because a content script cannot read from file:
, unless it is running on a page at the file://
scheme.
Note
To enable cross-origin requests, you have to explicitly grant permissions to your extension using thepermissions
array in your manifest file.
Cross-site request using background script.
The content script would request the functionality from the background via the messaging API. Here is an example of a very simple way of sending and getting the response of a request.
chrome.runtime.sendMessage({ method: 'POST', action: 'xhttp', url: 'http://www.stackoverflow.com/search', data: 'q=something'}, function(responseText) { alert(responseText); /*Callback function to deal with the response*/});
Background / event page:
/** * Possible parameters for request: * action: "xhttp" for a cross-origin HTTP request * method: Default "GET" * url : required, but not validated * data : data to send in a POST request * * The callback function is called upon completion of the request */chrome.runtime.onMessage.addListener(function(request, sender, callback) { if (request.action == "xhttp") { var xhttp = new XMLHttpRequest(); var method = request.method ? request.method.toUpperCase() : 'GET'; xhttp.onload = function() { callback(xhttp.responseText); }; xhttp.onerror = function() { // Do whatever you want on error. Don't forget to invoke the // callback to clean up the communication port. callback(); }; xhttp.open(method, request.url, true); if (method == 'POST') { xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); } xhttp.send(request.data); return true; // prevents the callback from being called too early on return }});
Remark: The messaging APIs have been renamed several times. If your target browser is not the latest Chrome version, check out this answer.
For completeness, here's a manifest file to try out my demo:
{ "name": "X-domain test", "manifest_version": 2, "permissions": [ "http://www.stackoverflow.com/search*" ], "content_scripts": { "js": ["contentscript.js"], "matches": ["http://www.example.com/*"] }, "background": { "scripts": ["background.js"], "persistent": false }}
I implemented the same thing using jquery its much simpler and it worked great too..
background.js
chrome.runtime.onMessage.addListener(function(request, sender, callback) { if (request.action == "xhttp") { $.ajax({ type: request.method, url: request.url, data: request.data, success: function(responseText){ callback(responseText); }, error: function(XMLHttpRequest, textStatus, errorThrown) { //if required, do some error handling callback(); } }); return true; // prevents the callback from being called too early on return }});
contentscript.js
chrome.runtime.sendMessage({ method: 'POST', action: 'xhttp', url: 'http://example-url.com/page.php', data: "key=value" }, function(reponseText) { alert(responseText); });
But make sure manifest.json file has required permissions and jquery js file
"permissions": [ "tabs", "activeTab", "http://example-url.com/*" ], "content_scripts": [ { "js": [ "jquery-3.1.0.min.js", "contentscript.js" ], "matches": [ "https://example-ssl-site.com/*" ] }], "background": { "scripts": [ "jquery-3.1.0.min.js", "background.js" ] }