In the next project, I was faced with the need to actively work with cross-domain requests for ajax, the topic, as I see it on Habré, was not particularly raised or covered, so I decided to share my experience with readers.
Suppose we have a website
http://name.my
and we want to use ajax on it and what do we get?
- Request for
http://name.my/ajax.php
(I will write php everywhere so that everyone is comfortable, he himself worked with java) will give us the answer without any problems - Request for
http://google.com/
access error - Attempt to reach
https://name.my/ajax.php
also fail, the protocol has changed http://name.my:81/ajax.php
and another port in the address will ruin the raspberries
Task: find a cross-browser solution for sending requests that will work: ie7 +, opera 9.6+, ff 3+, chrome, safari. And also since I also had to turn from http to https there should not be a “mixed content” message in ie.
JQuery was used as a library on the site and there is no built-in cross domain query mechanism in it (it appeared in 1.5 that it was possible to organize jsonp but this did not always work), the search for plug-ins also produced no results. Therefore, having broken off with simple ways (which was expected in principle), I went to Google, which also does not give an obvious answer - I found the description of methods more or the things that did not suit me (for example, in dojo there are releasing such requests, but changing all js the site is very labor-intensive).
The following techniques could be used to solve the problem:
- postMessage
- Jsonp
- CORS
- document.domain methods
- window.name Transport
- Server-side proxy
- CRAZY IFRAME STUFF
- flash
Newbie, at the sight of this list will be horrified (in principle, I was also not thrilled). So our task is to find the best way to solve a problem that would not create extra crutches on the site.
1) postMessage is a new feature of the HTML5 standard, allows you to send messages from one window to another, while the content of the windows can be from different domains. An example implementation of targetWindow.postMessage (message, targetOrigin); targetWindow - window where we send the request, message - message, targetOrigin target domain to be opened in the window, specifying “*” as a domain is allowed, and there can be any domain.
2) JSONP (JSON Padding) or “JSON with padding” is an extension of JSON when the name of the callback function is specified as an input argument. Using the tag, we can refer to other domains, but the result will come in the form of a json response, which we cannot process, jsonp offers the following solution: when transferring the name of the function to the server, we receive in the response not bare data, but parseResponse ({“paper”: "A4", "count": 5}), which calls the parseResponse function.
3) CORS is a big topic, so I’ll tell you briefly who are interested in the W3c documentation in WLc. XMLHTTPRequest 2 is a new request specification that works and is called like a normal XMLHTTPRequest (in other words, this is XDomainRequest), but now the following is added to the http header:
Access-Control-Allow-Origin determines which domains are allowed to connect
Access-Control-Allow-Credentials specifies the permissions to execute a request (Access-Control-Allow-Credentials: "Access-Control-Allow-Credentials" ":" true true:% x74.72.75.65; "true", case-sensitive )
Access-Control-Max-Age - how long the results will be cached.
You can also determine the available methods (GET, POST), all additional header fields you can see in the specification.
The main problem of the method is that not all browsers support it, and for those who want to use the IE implementation, XDomainRequest, do not forget that IE is in its repertoire and will not allow you to make a request from the http to https protocol, although only requests with https on http), but this is ie.
4) document.domain will suit us if we want to communicate with 2 sites on the general superdomain, that is, test1.name.my and test2.name.my. There is no normal request between these sites, however, the document has a domain property that we can change for both windows to name.my and communicate in the usual way via an iframe.
5) window.name Transport - is to change the name property on windows and thus transfer the properties of our serialized data through the text.
6) Server-side proxy - the simplest solution is to proxy the request by the server. That is, name.my makes a special request, for example, to a special URL of the
name.my/proxy/name2.my/test.html type, and the name.my server proxies it to
name2.my/test.html .

7) CRAZY IFRAME STUFF - the essence of the method is that iframes, even on different domains, can communicate with each other by changing the identifiers of address fragments (the identifier is what is in the address after the '#') By successive changes of the # fragment a stream of data is formed that can be transmitted in both directions. Since the fragment identifier is text, then all the data for transmission has to be (de) serialized, that is, if you need to turn it into JSON + 2 iframe, in order not to affect the address of the visible window.
8) flash - use flash as an intermediate interface (a separate topic, all the details of which are also drawn to the article)
Searching the internet I found a wonderful library
easyxdm.net/wp . The most delicious thing is the method of work, the fastest and most modern method is chosen based on the browser and its version.
- IE6 and IE7 - a flash flashing is used (Microsoft Security Bulletin MS11-018)
- IE8 + - used by postMessage
- Opera 9+ - used by postMessage
- Firefox 1-2 - ifame is used
- Firefox 3+ - used by postMessage
- Safari 4+ - used by postMessage
- Chrome 2+ - used by postMessage
For other browsers that do not support postMessage, exchange-based technology will be used. #Hash Library functions are not limited to ajax, but the conversation will be mostly about it.
So, let's start with the implementation of the ajax request using easyxdm.
We create directly a proxy object for sending requests:
var xhr = new easyXDM.Rpc ({
remote: "http://name.my/cors/index.html" // path to the provider
}, {
remote: {
request: {}
}
});
easyXDM is if you can call it a static class that does not have a constructor and implements a singleton pattern.
Helmet request itself:
xhr.request (
{
url: "pathRelativeToRemote / getrest /", // address of our request
method: "POST",
data: {foo: "bar"}
}, function (response) {// response result processing function
alert (response.status);
alert (response.data);
}
);
Now in more detail: with the first parameter we set the basic settings, in particular, here we indicate the path to the previously prepared file “provider” (it is in the archive with the build in the cors folder), which should be found
')
I'm on a remote server, it will proxy requests to the url we need and send us answers using one of the available methods.
However, do not forget that here you will also need to enter the path to the flash drive (flash drive is also attached to the lib), through which the old versions of IE will establish a connection.
Next, we create the structure of the remote methods, now the
request is declared there (in the
name.my/cors/index.html file, a similar structure of the methods should also be created)
Calling the xhr.request function
, we
send a request to our proxy file
name.my/cors/index.html , which knocks on the url and passes the
data parameter there, using normal ajax, having received the answer, it sends the data (if necessary, breaking the answer into parts) to our host, where the callback is called, which we passed to the last parameter.
We’ll touch on the
name.my/cors/index.html file a little bit
; it is an indispensable part of our request; firstly, it organizes the reverse transport and data reception. Secondly, he has a wonderful bun - he implements CORS with his own means:
var useAccessControl = true; // allow (true) or disable (false) to accept headers from the server (so that by chance the server will not allow sending data to a third-party domain)
var alwaysTrustedOrigins = [(/\.easyxdm\.net/), (/ xdm1 /)]; // list of allowed servers
var remote is an easyXDM object in which we must implement the structure of remote methods.
And also do not forget to connect a small “library” json2.js which for old browsers implements a JSON object actively used in easyXDM (and easyXDM does not prevent you from creating your serializer and passing it as a parameter, although it seems to me this is a very rare need).
My project had a task to send a lot of different forms according to Ajax, respectively, I needed a handy tool that serializes and sends the specified form to ajax. The solution was found immediately in the face of the jQuery Form plugin, but the plugin is tied to jq and therefore refuses to send cross domain requests.
Let me give you a simple way to embed our cross-domain query into a plugin without affecting the structure and leaving jQuery as the handler for the usual ajax.
We have in html form (what the plug-in will do to the excitement of this will take us a little):
<form action = "name2.my" id = "myform" method = "POST"> ... </ form>
Prepare our object for cross-domain query in advance:
crossAjax = new easyXDM.Rpc ({
remote: 'name2.my/cors', // our provider on the remote server
swf: 'name.my/easyxdm.swf'
}, {
remote: {
request: {}
}
});
The following is the plug-in connection code in which all form fields are automatically serialized, and the url to which we send the form is taken from the action of the form itself (as well as the method)
$ ('# myform'). ajaxForm ({
beforeSubmit: beforeSubmit,
success: showResponse
});
This is the method in which we process the result; we do not affect it at all:
showResponse = function (responseText, statusText, xhr, form) {
here we do something with our answer
}
But the main focus will be in beforeSubmit, the method is called before the form is submitted, accordingly here we can both get the already serialized data and interrupt the further sending of the request (which we need):
beforeSubmit = function (arr, form, options) {if (options.url.indexOf (location.host) <0) {// if the host is remote then use our method var json = {}; for (var i = 0; i <arr.length; i ++) {// convert the serialized form data into a normal js object ready for our serialization (the form itself transmits them in a very strange way) json [arr [i] .name] = arr [i] .value; } crossAjax.request ({// send cross domain request, substituting our parameters url: options.url, method: "POST", data: json}, function (response) {switch (response.status) {// parse the answer case 200: showResponse (JSON.parse (response.data), response.status, arr, form) break; default: alert ("Error:" + response.status); break;}}); return false; // stop the native ajax request from jQ}}
Something like this can easily solve a problematic task. Working examples can be found on the library website. At this point, I complete my first “habrapost”.
Library itself