482

Here are two pages, test.php and testserver.php.

test.php

<script src="scripts/jq.js" type="text/javascript"></script>
<script>
    $(function() {
        $.ajax({url:"testserver.php",
            success:function() {
                alert("Success");
            },
            error:function() {
                alert("Error");
            },
            dataType:"json",
            type:"get"
        }
    )})
</script>

testserver.php

<?php
$arr = array("element1",
             "element2",
             array("element31","element32"));
$arr['name'] = "response";
echo json_encode($arr);
?>

Now my problem: when both of these files are on the same server (either localhost or web server), it works and alert("Success") is called; If it is on different servers, meaning testserver.php on web server and test.php on localhost, its not working, and alert("Error") is executing. Even if the URL inside ajax is changed to http://domain.com/path/to/file/testserver.php

fibono
  • 671
  • 9
  • 23
Firose Hussain
  • 4,831
  • 3
  • 13
  • 4
  • 38
    For people stopping by. Read this to have an idea how cross domain javascript calls work http://stackoverflow.com/a/11736771/228656 – Abdul Munim Aug 02 '12 at 09:34
  • 1
    **I wrote an answer for this question here: [Loading cross domain html page with jQuery AJAX](http://stackoverflow.com/questions/15005500/loading-cross-domain-html-page-with-jquery-ajax/17299796#17299796)** – _the last one, supports https_ – jherax Jun 26 '14 at 16:02

14 Answers14

414

Use JSONP.

jQuery:

$.ajax({
     url:"testserver.php",
     dataType: 'jsonp', // Notice! JSONP <-- P (lowercase)
     success:function(json){
         // do stuff with json (in this case an array)
         alert("Success");
     },
     error:function(){
         alert("Error");
     }      
});

PHP:

<?php
$arr = array("element1","element2",array("element31","element32"));
$arr['name'] = "response";
echo $_GET['callback']."(".json_encode($arr).");";
?>

The echo might be wrong, it's been a while since I've used php. In any case you need to output callbackName('jsonString') notice the quotes. jQuery will pass it's own callback name, so you need to get that from the GET params.

And as Stefan Kendall posted, $.getJSON() is a shorthand method, but then you need to append 'callback=?' to the url as GET parameter (yes, value is ?, jQuery replaces this with its own generated callback method).

AJ Meyghani
  • 3,791
  • 1
  • 28
  • 33
BGerrissen
  • 19,774
  • 3
  • 36
  • 40
  • 2
    Why do you need to return `callbackName('/* json */')` instead of `callbackName(/* json */)`? – Eric Oct 23 '11 at 12:41
  • 3
    @eric the callback expects a JSON string. Theoretically, an object might work as well, but not sure how jQuery responds to this, it might throw an error or fail silently. – BGerrissen Oct 24 '11 at 10:27
  • I'm getting the following error. SyntaxError: missing ; before statement {"ResultCode":2}. Where {"ResultCode":2} is response. Please advice. – user2003356 Jan 23 '14 at 08:59
  • @user2003356 looks like you are returning plain JSON instead of JSONP. You need to return something like: callbackFunction({"ResultCode":2}). jQuery adds the GET parameter 'callback' to the request, that's the name of the callback function jquery uses and should be added to the response. – BGerrissen Feb 21 '14 at 13:49
  • The comma at the end of error: function(){...}, appears to cause an error. I'd take it out but edits must be 6 characters. so. that's good. – user1566694 Mar 19 '14 at 18:49
  • The explanation given by @BGerrissen worked well for me after adding `crossDomain: true,` from the [docs](http://api.jquery.com/jQuery.ajax/), " crossDomain (default: false for same-domain requests, true for cross-domain requests) Type: Boolean If you wish to force a crossDomain request (such as JSONP) on the same domain, set the value of crossDomain to true. This allows, for example, server-side redirection to another domain. (version added: 1.5) " – srj May 13 '14 at 17:36
  • There is http://jsonp.jit.su/ it's a free JSON Proxy "Enables cross-domain requests to any JSON API." And it's on Github https://github.com/afeld/jsonp – Joël May 14 '14 at 18:57
  • 2
    It's 2016. CORS is now a widely supported standard, as opposed to JSONP which can only be described as a hack. @joshuarh's answer below should be the preferred one now. – Vicky Chijwani Jul 20 '16 at 09:16
  • why is it necessary to get the callback method in server? – Sudip Bhandari Jul 26 '16 at 08:23
  • Keep in mind that using cross domain JSONP can possible open up your website also to cross side scripting attacks if the remote API has a vurnability. – Raymond Nijland Mar 24 '19 at 23:15
206

JSONP is a good option, but there is an easier way. You can simply set the Access-Control-Allow-Origin header on your server. Setting it to * will accept cross-domain AJAX requests from any domain. (https://developer.mozilla.org/en/http_access_control)

The method to do this will vary from language to language, of course. Here it is in Rails:

class HelloController < ApplicationController
  def say_hello
    headers['Access-Control-Allow-Origin'] = "*"
    render text: "hello!"
  end
end

In this example, the say_hello action will accept AJAX requests from any domain and return a response of "hello!".

Here is an example of the headers it might return:

HTTP/1.1 200 OK 
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "c4ca4238a0b923820dcc509a6f75849b"
X-Runtime: 0.913606
Content-Length: 6
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Date: Thu, 01 Mar 2012 20:44:28 GMT
Connection: Keep-Alive

Easy as it is, it does have some browser limitations. See http://caniuse.com/#feat=cors.

packmate
  • 3,979
  • 2
  • 20
  • 24
  • 12
    Jsonp did not support post, put and delete. Your solution works great. – TonyTakeshi Jul 23 '12 at 04:40
  • 35
    in PHP header("Access-Control-Allow-Origin: *"); – SparK Sep 20 '12 at 14:46
  • @SparK This code is fine when am using xmlhttpRequest.But not working when am using jquery.Post... – Warrior Jan 02 '13 at 13:27
  • 9
    @Warrior If you're using jQuery's `.post()` method you have to enable cross-domain support in jQuery. It is done with this: `$.support.cors = true`. – Friederike Apr 26 '13 at 12:29
  • 4
    FYI - the official name for this is 'CORS' (Cross Origin Resource Sharing). More info: http://en.wikipedia.org/wiki/Cross-origin_resource_sharing – Dan Esparza Apr 30 '13 at 14:42
  • 6
    It's just lazy to not whitelist particular domains and instead allow access from all domains... – Jasper Jan 22 '14 at 18:04
  • 21
    What are the security implications of configuring a server in this manner? – Jon Schneider Jan 24 '14 at 03:12
  • 4
    @JonSchneider the problem with this approach (just allowing any origin with *) is that any malicious page can capture the user's information on that server. Gmail had this problem once. It was inadvertently disclosing the user's contacts list. – Sebastián Grignoli Dec 11 '14 at 21:10
  • 20
    It would be better to allow only those domains that you want to share the data with instead of using the wilcard "*". – Sebastián Grignoli Dec 11 '14 at 21:11
32

You can control this via HTTP header by adding Access-Control-Allow-Origin. Setting it to * will accept cross-domain AJAX requests from any domain.

Using PHP it's really simple, just add the following line into the script that you want to have access outside from your domain:

header("Access-Control-Allow-Origin: *");

Don't forget to enable mod_headers module in httpd.conf.

Adorjan Princz
  • 11,208
  • 3
  • 32
  • 25
20

You need to have a look at Same Origin Policy:

In computing, the same origin policy is an important security concept for a number of browser-side programming languages, such as JavaScript. The policy permits scripts running on pages originating from the same site to access each other's methods and properties with no specific restrictions, but prevents access to most methods and properties across pages on different sites.

For you to be able to get data, it has to be:

Same protocol and host

You need to implement JSONP to workaround it.

admdrew
  • 3,600
  • 4
  • 22
  • 39
Sarfraz
  • 355,543
  • 70
  • 511
  • 562
18

I had to load webpage from local disk "file:///C:/test/htmlpage.html", call "http://localhost/getxml.php" url, and do this in IE8+ and Firefox12+ browsers, use jQuery v1.7.2 lib to minimize boilerplate code. After reading dozens of articles finally figured it out. Here is my summary.

  • server script (.php, .jsp, ...) must return http response header Access-Control-Allow-Origin: *
  • before using jQuery ajax set this flag in javascript: jQuery.support.cors = true;
  • you may set flag once or everytime before using jQuery ajax function
  • now I can read .xml document in IE and Firefox. Other browsers I did not test.
  • response document can be plain/text, xml, json or anything else

Here is an example jQuery ajax call with some debug sysouts.

jQuery.support.cors = true;
$.ajax({
    url: "http://localhost/getxml.php",
    data: { "id":"doc1", "rows":"100" },
    type: "GET",
    timeout: 30000,
    dataType: "text", // "xml", "json"
    success: function(data) {
        // show text reply as-is (debug)
        alert(data);

        // show xml field values (debug)
        //alert( $(data).find("title").text() );

        // loop JSON array (debug)
        //var str="";
        //$.each(data.items, function(i,item) {
        //  str += item.title + "\n";
        //});
        //alert(str);
    },
    error: function(jqXHR, textStatus, ex) {
        alert(textStatus + "," + ex + "," + jqXHR.responseText);
    }
});
Whome
  • 9,559
  • 6
  • 43
  • 59
  • 1
    **I wrote an answer for this question here: [Loading cross domain html page with jQuery AJAX](http://stackoverflow.com/questions/15005500/loading-cross-domain-html-page-with-jquery-ajax/17299796#17299796)** – _the last one, supports https_ – jherax Jun 26 '14 at 16:08
  • For the firest point: in PHP add this line to the script: `header("Access-Control-Allow-Origin: *");` – T30 Jan 15 '16 at 13:30
  • 1
    @whome thank you VERY much for your answer. You helped me a lot. Cheers. – Luis Milanese Dec 12 '19 at 18:59
10

It is true that the same-origin policy prevents JavaScript from making requests across domains, but the CORS specification allows just the sort of API access you are looking for, and is supported by the current batch of major browsers.

See how to enable cross-origin resource sharing for client and server:

http://enable-cors.org/

"Cross-Origin Resource Sharing (CORS) is a specification that enables truly open access across domain-boundaries. If you serve public content, please consider using CORS to open it up for universal JavaScript/browser access."

Jason
  • 2,059
  • 2
  • 21
  • 22
9

This is possible, but you need to use JSONP, not JSON. Stefan's link pointed you in the right direction. The jQuery AJAX page has more information on JSONP.

Remy Sharp has a detailed example using PHP.

Paul Schreiber
  • 12,094
  • 4
  • 36
  • 61
9

I use Apache server, so I've used mod_proxy module. Enable modules:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Then add:

ProxyPass /your-proxy-url/ http://service-url:serviceport/

Finally, pass proxy-url to your script.

imilbaev
  • 844
  • 11
  • 19
8

Browser security prevents making an ajax call from a page hosted on one domain to a page hosted on a different domain; this is called the "same-origin policy".

Jacob Mattison
  • 47,745
  • 8
  • 102
  • 120
5

There are few examples for using JSONP which include error handling.

However, please note that the error-event is not triggered when using JSONP! See: http://api.jquery.com/jQuery.ajax/ or jQuery ajax request using jsonp error

Community
  • 1
  • 1
BillyTom
  • 1,981
  • 1
  • 13
  • 25
4

From the Jquery docs (link):

  • Due to browser security restrictions, most "Ajax" requests are subject to the same origin policy; the request can not successfully retrieve data from a different domain, subdomain, or protocol.

  • Script and JSONP requests are not subject to the same origin policy restrictions.

So I would take it that you need to use jsonp for the request. But haven't tried this myself.

3

I know 3 way to resolve your problem:

  1. First if you have access to both domains you can allow access for all other domain using :

    header("Access-Control-Allow-Origin: *");

    or just a domain by adding code bellow to .htaccess file:

    <FilesMatch "\.(ttf|otf|eot|woff)$"> <IfModule mod_headers.c> SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.net|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0 Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin </IfModule> </FilesMatch>

  2. you can have ajax request to a php file in your server and handle request to another domain using this php file.

  3. you can use jsonp , because it doesn't need permission. for this you can read our friend @BGerrissen answer.
Ali_Hr
  • 2,286
  • 2
  • 17
  • 27
0

For Microsoft Azure, it's slightly different.

Azure has a special CORS setting that needs to be set. It's essentially the same thing behind the scenes, but simply setting the header joshuarh mentions will not work. The Azure documentation for enabling cross domain can be found here:

https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-cors-consume-javascript

I fiddled around with this for a few hours before realizing my hosting platform had this special setting.

Josh Schultz
  • 797
  • 10
  • 30
0

it works, all you need:

PHP:

header('Access-Control-Allow-Origin: http://www.example.com');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');

JS (jQuery ajax):

var getWBody = $.ajax({ cache: false,
        url: URL,
        dataType : 'json',
        type: 'GET',
        xhrFields: { withCredentials: true }
});