- How to Send Cross Domain AJAX Request with jQuery
- 1).Using JSONP
- 2).Uing CORS (Cross-origin resource sharing)
- Cross Domain Ajax Request With Cookies (CORS)
- The Problem
- CORS vs JSONP
- How to Pass Cookies on a Cross-Domain AJAX Request from Browser to Server
- Configuring the AJAX Request
- AJAX Parameter: withCredentials
- AJAX Request
- Server Headers
- Header: Access-Control-Allow-Origin
- Header: Access-Control-Allow-Credentials
- Кроссдоменный AJAX запрос: раз и навсегда про клиентскую и серверную часть
- 1. JSONP
- 2. Заголовки
- Почему мы?
How to Send Cross Domain AJAX Request with jQuery
In this tutorial, I explained how to send Cross Domain AJAX Request with jQuery and PHP. Different methods of handling cross domain AJAX requests are covered in this article.
1).Using JSONP
We can send cross domain AJAX requests using JSONP. Below is the simple JSONP Request:
$.ajax(< url : "http://hayageektest.appspot.com/cross-domain-cors/jsonp.php", dataType:"jsonp", >); function mycallback(data)
jsonp.php response is:
when the JSONP request is successful, mycallback function is called.
If you want the function handling automatically, you can use the below approach. In this case, you need not have any extra function. You can get the server response in success callback
jsonp.php source code:
$arr =array(); $arr['name']="Ravishanker"; $arr['age']=32; $arr['location']="India"; echo $callback.'(' . json_encode($arr) . ')'; ?>
This works in all the browsers but the problem is: JSONP supports only GET method. POST method is not allowed.
2).Uing CORS (Cross-origin resource sharing)
Browser does not allow cross domain AJAX requests due to security issues. Cross-domain requests are allowed only if the server specifies same origin security policy.
Read more about Cross-origin resource sharing (CORS) : Wiki
To enable CORS, You need to specify below HTTP headers in the server.
Access-Control-Allow-Origin – Name of the domain allowed for cross domain requests. * indicates all domains are allowed.
Access-Control-Allow-Methods – List of HTTP methods can be used during request.
Access-Control-Allow-Headers – List of HTTP headers can be used during request.
In PHP, you can use the below code to set the headers.
header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Content-Range, Content-Disposition, Content-Description');
Below the sample code which handles Cross Domain AJAX POST requests: post.php
CORS works fine in all the latest browsers, but IE8 and IE9 don’t support this.
IE8,IE8 handles AJAX request using window.XDomainRequest. So We can use this jQuery plugin: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest
In order to use XDomainRequest in IE, request must be:
a). Only GET or POST
When Posting, the data will always be sent with a Content-Type of text/plain
b). Only HTTP or HTTPS
Protocol must be the same scheme as the calling page
c). Always asynchronous
Follow the steps for XDomainRequest:
Step 1). Add the script in
Step 2). You need to set contentType value text/plain in $.ajax request.
var contentType ="application/x-www-form-urlencoded; charset=utf-8"; if(window.XDomainRequest) //for IE8,IE9 contentType = "text/plain"; $.ajax(< url:"http://hayageektest.appspot.com/cross-domain-cors/post.php", data:"name=Ravi&age=12", type:"POST", dataType:"json", contentType:contentType, success:function(data) < alert("Data from Server"+JSON.stringify(data)); >, error:function(jqXHR,textStatus,errorThrown) < alert("You can not send Cross Domain AJAX requests: "+errorThrown); >>);
Below is the sample code, works in all the browsers.
post.php source code:
Cross Domain Ajax Request With Cookies (CORS)
Passing cookies in Cross Origin AJAX requests across domains can be accomplished as long as the proper configuration is made on the browser and server side. This tutorial outlies the correct settings to ensure the request doesn’t violate the CORS policy and the request succeeds.
The Problem
Your code makes an AJAX request (with jQuery, though this issue isn’t specific to jQuery) cross-domain and the server expects the cookies from the browser to be passed. However they are not sent in the request from the browser.
CORS vs JSONP
I’m not going to go into full details here – just hit on the tip top level. A plethora of information is available on the internet for these topics.
CORS (Cross-origin resource sharing) is a mechanism implemented by browsers to ensure that malicious requests to a server can’t be made – it’s a restriction method. It respects the Same-origin policy for security reasons.
First off, JSONP technically is a way to solve this problem, however I don’t advise it as the correct solution. It is an old and outdated technology and has security flaws. The basics of it is that a request to the server (with cookies) is made by the browser for a Javascript function. A function is returned and the browser can then use it to process the response as needed.
How to Pass Cookies on a Cross-Domain AJAX Request from Browser to Server
There are two things that need to be done here:
- Configure your AJAX request to pass cookies
- Set the response headers to conform with CORS
Configuring the AJAX Request
You need to tell your AJAX request to pass credentials with this bit of code:
AJAX Parameter: withCredentials
This parameter indicates if a cross-domain request should send credentials (which include cookies, TLS certificates, authorization headers, etc.).
AJAX Request
Here is a full example of what the basic AJAX request should look like.
The browser is now passing cookies (credentials) to the server.
Server Headers
The server now needs to respect the CORS request and respond with the correct headers. There are two headers that need to be set for this to work roundtrip.
Header: Access-Control-Allow-Origin
This needs to be set to the domain from which the browser made the request. So if the URL in the browser is:
and makes the AJAX request to:
then this header needs to be set as so:
What this header says is that this is the only domain that is allowed to make this cross-origin request – essentially the two domains are the same domain. A request from any other domain will fail the Same-origin policy of CORS and the request will fail.
Header: Access-Control-Allow-Credentials
This header needs to be set to true in this scenario.
This is simply a partner header to the withCredentials parameter passed in the AJAX request. It’s saying that credentials are allowed to be passed through this request and response.
Thanks! but in my case it still does not work. Page: my.foo.com
ajax:
$.ajax( type: “post”,
url: ‘http://192.168.0.204:8080/bar/search’,
contentType : “application/json;charset=utf-8”,
dataType: “json”,
xhrFields: < withCredentials: true >,
… Server:
Access-Control-Allow-Origin:http://my.foo.com
Access-Control-Allow-Credentials:true Is it the reason that used ip not hosts?
At quick glance yes I believe you are right. http://192.168.0.204:8080 does not equal http://my.foo.com/ The domain name and port do not match.
Yeah, pass cookie successfully need another condition: both sites must have the common part, e.g front.foo.com, back.foo.com. And do you know if could do not need client to configure xhrFields: < withCredentials: true >, in ajax explicitly, just by have some configuration in Nginx could support this? e.g. dynamically add withCredentials: true in request header.
Real quick – I should expand on my prior comment a bit by saying that the Same-origin policy has strict rules regarding what domains can make a request from another domain. See here. There may be an Nginx option but I do not know of it personally.
Hi,
I have 2 website there I can access by http or https.
So, this step works :
1) (http) Connection to website 1 http://www.site1.com with form login (user1, pa$$word1) and get a cookie
2) (https) Closing browser windows and connect to https://www.site2.com
3) (https) Ajax request to https://www.site1.com from https://www.site2.com and get the cookie information
4) Display user1 and pa$$word1 on https://www.site2.com
5) OK, it works
But, this step does not work :
1) (https) Connection to website 1 https://www.site1.com with form login (user1, pa$$word1) and get a cookie
2) (https) Closing browser windows and connect to https://www.site2.com
3) (https) Ajax request to https://www.site1.com from https://www.site2.com and get the cookie information
4) Display user1 and pa$$word1 on https://www.site2.com
5) NOOOO ! It does not work . The problem come from step 1 (https)
Could you help me ?
It’s hard to say 100% why without debugging in a browsers dev console and/or seeing your server header settings, but most likely the issue is that the server is responding with http://www.site1.com for the Access-Control-Allow-Origin header, which is great for the first scenario but on the second scenario it should be set to https://www.site1.com – the exact domain that made the request (protocol, subdomain, port). You may need to get “smarter” on the server side to return the correct domain in the response based on which domain made the request in order to support multiple requesting domains. What I do is create a whitelist of approved protocol/subdomain/port combinations in the server. Then compare the request referrer URL with that list to see if the request should be authorized to pass this response back. This allows you to support multiple requesting domains while still adhearing to the one domain response allowed for the Access-Control-Allow-Origin header. The other option would be to respond with * for the Access-Control-Allow-Origin header. This is a wildcard, meaning any domain can make this request. But this brings in a new level of security concerns that you’ll need to consider. For a site like Facebook that wants their services to be accessible and embedded on any domain this may suffice, but typically for more closed off services that should be accessed from only website they are created for I’d suggest not using the wildcard option.
Hi,
Thanks for your answer
I understand now better the matter 🙂
The problem occures because I authenticate on https://www.site1.com with my username and password.
When I go on https://www.site2.com, my “ajaxfile.js” connect to https://site1.com (without www).
That mean that the server consider that without “www” is not the same domain. (I use Symfony with fosuserbundle)
Do you have an idea how to solve this problem ?
I don’t now where the user will conect to (with or without www)
Thanks a lot for your help.
My gut reaction is that the issue still lies in how the ccess-Control-Allow-Origin header is being set but I feel this may be getting a bit out of the bounds of what I can troubleshoot.
Кроссдоменный AJAX запрос: раз и навсегда про клиентскую и серверную часть
Каждый раз, как в первый раз с этим кроссдоменным AJAX.
1. JSONP
Клиентская часть выглядит так:
$.ajax( type: ‘GET’, // jsonp всегда будет отправляться GET’ом, даже если принудительно указать POST
url: ‘http://. ‘,
data: ( ‘var1’:value1,
‘var2’:value2
>),
dataType: ‘jsonp’,
jsonp: ‘mycallbackfunction’,
crossDomain: true,
cache: false,
complete: function(xhr, status) <>,
error: function(xhr, status, message) <>,
success: function(data, status, xhr) <>
>);
Жирным выделено самое главное в этом jQuery AJAX запросе:
- dataType: ‘jsonp’ — говорим, что хотим получить ответ в jsonp-формате;
- jsonp: ‘mycallbackfunction’ — говорим, что функция обратного вызова будет называться mycallbackfunction;
- crossDomain: true — говорим, что запрос является кроссдоменным.
echo $_GET[‘mycallbackfunction‘].'(‘.json_encode($arrayData).’)’;
Тут обратите внимание на GET параметр mycallbackfunction — он тут главный.
Обратите внимание, что в этом случае мы никакие специальные заголовки не отдаем.
2. Заголовки
В этом случае мы можем позволить себе простейший запрос:
$.ajax( type: ‘POST’, // В отличие от jsonp, тут можно использовать и POST, и все остальное
url: ‘http://. ‘,
data: ( ‘var1’:value1,
‘var2’:value2
>),
dataType: ‘json’,
crossDomain: false,
cache: false,
complete: function(xhr, status) <>,
error: function(xhr, status, message) <>,
success: function(data, status, xhr) <>
>);
Обратите внимание, что здесь мы даже не говорим, что запрос кроссдоменный (crossDomain: false) и ждем от сервера вполне понятный JSON, а не «диковенный» JSONP.
Конечно, браузеры нас завернут за такой запрос аргументируя, что отсутствует заголовок CORS «Access-Control-Allow-Origin» .
Чтобы все отработало как нужно, добавим в скрипт следующие заголовки:
header(‘Access-Control-Allow-Origin: *’);
header(‘Access-Control-Allow-Headers: Origin,Content-Type,Accept,X-Requested-With’);
В первой строке вместо * лучше указать конкретный домен — так будет безопаснее.
Во второй строке работать будет и только с X-Requested-With, а Origin, Content-Type, Accept были подсмотрены в одном из запросов одного из сервисов Яндекса.