0

I was trying to write a cross domain request (e.g., Google Finance resource) in JavaScript from client-side (the browser) by following a template like below mentioned here:

function createCORSRequest(method, url) {
  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) {
    xhr.open(method, url, true);    
  } else if (typeof XDomainRequest != "undefined") {
    xhr = new XDomainRequest();
    xhr.open(method, url);    
  } else {    
    // Otherwise, CORS is not supported by the browser.
    xhr = null;    
  }
  return xhr;
}

var url = 'http://finance.google.com/finance/info?client=ig&q=NASDAQ:GOOGL';
var xhr = createCORSRequest('GET', url);
if (!xhr) {
  throw new Error('CORS not supported');
}

// Response handlers.
xhr.onload = function() {
    var text = xhr.responseText;
    var jsonReturend = JSON.parse(text);
    console.log(jsonReturend)
};

xhr.onerror = function() {
    alert('Woops, there was an error making the request.');
};

xhr.send();

But it doesn't work because (I think) 'finance.google.com' doesn't include Access-Control-Allow-Origin: in its response headers, which is understandable. However, I tried another suggested method on StackOverflow post here to use JSONP as follows:

$.ajax({
    url: 'http://finance.google.com/finance/info?client=ig&q=NASDAQ:GOOGL', 
    jsonp: "callback",
    dataType: "jsonp", 
    data: {},
    // Work with the response
    success: function( response ) {
        console.log( response ); // server response
    }
});

and it works (that is, I got the expected JSON back)! As a newbie to web development and JS in general, I am not sure why AJAX call via jQuery's JSONP is working whereas it fails in pure JavaScript. My questions are:

  1. What is JSONP doing differently to make things work? Or is it simply because 'finance.google.com' is allowing JSONP type requests (but not CORS type requests)?
  2. Is it possible to make it work by strictly using JavaScript? If so, how could I achieve that?

Thank you all for your answers!

Community
  • 1
  • 1
user1330974
  • 2,500
  • 5
  • 32
  • 60

2 Answers2

2

Cross origin XHR requests have to be allowed by the server using Access-Control-Allow-Origin. JSONP is a mechanism to work around it.

This wiki page contains very good description of why it works. See the Script element injection section.

https://en.wikipedia.org/wiki/JSONP

This stackoverflow answer shows how to use pure javascript to make jsonp calls.

Can anyone explain what JSONP is, in layman terms?

Community
  • 1
  • 1
Kalpana
  • 198
  • 5
  • Thank you for the response. I understand now that jQuery is doing a lot of work for us in the background to make JSONP work. But in the last link you shared where it shows how to do it in pure JavaScript, the code looks like this: var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { //we never enter here because 'xhr' seems to always error }; }; xhr.open("GET", "my-google-finance-link-in-question", true); xhr.send(); It doesn't seem to work. Could you help me explain as to why? Thank you! – user1330974 Sep 03 '16 at 13:32
  • 1
    For the jsonp requests you need to create a script tag, point the src tag to the request url with callback and then append it to the head section of the html. This will make a normal script request but because we have specified a callback in the request url, the callback function will be invoked once the jsonp request is completed. The code snippet is as belows: `var tag = document.createElement("script"); tag.src = 'somewhere_else.php?callback=foo'; document.getElementsByTagName("head")[0].appendChild(tag);` The callback function foo is called once the jsonp request completes. – Kalpana Sep 03 '16 at 22:45
1

First, I will show the response of the request here:

// [ { "id": "694653" ,"t" : "GOOGL" ,"e" : "NASDAQ" ,"l" : "796.87" ,"l_fix" : "796.87" ,"l_cur" : "796.87" ,"s": "2" ,"ltt":"4:00PM EDT" ,"lt" : "Sep 2, 4:00PM EDT" ,"lt_dts" : "2016-09-02T16:00:02Z" ,"c" : "+5.47" ,"c_fix" : "5.47" ,"cp" : "0.69" ,"cp_fix" : "0.69" ,"ccol" : "chg" ,"pcls_fix" : "791.4" ,"el": "796.01" ,"el_fix": "796.01" ,"el_cur": "796.01" ,"elt" : "Sep 2, 7:45PM EDT" ,"ec" : "-0.86" ,"ec_fix" : "-0.86" ,"ecp" : "-0.11" ,"ecp_fix" : "-0.11" ,"eccol" : "chr" ,"div" : "" ,"yld" : "" } ] 

Actually, the XHR request in you javascript template works. The error happen when the script trying to parse the JSON text (var jsonReturend = JSON.parse(text);). It happen because the text that you will parse is not a good json text. You see the response above, it has two slashes in the beginning. JSON should not have it.
So, to make the text parseable by JSON.parse() you need to remove those slashes. Here is the fix of your javascript block:

// Response handlers.
xhr.onload = function() {
    var text = xhr.responseText;
    text    = text.replace("// ","");// replace slashes, make it a pure JSON text
    var jsonReturend = JSON.parse(text);
    console.log(jsonReturend)
};

Now, JSON.parse() will be able to parse the text.
JSONP in jquery ajax request is only an option to format the response of request. It has nothing to do with the request itself. If you set the ajax option to dataType:"jsonp", the script will work. And if you set it to dataType:"json" the script will not work. The dataType option defines how the response will be formatted.
Of course, you can use dataType:"text" too. But you cannot directly use it as object or JSON.

Oki Erie Rinaldi
  • 1,835
  • 1
  • 22
  • 31
  • Thank you for the tip. I replaced the code in `xhr.onload` as you suggested, but it still gives me `xhr.onerror` and also the error message that reads, 'XMLHttpRequest cannot load http://finance.google.com/finance/info?client=ig&q=NASDAQ:GOOGL. No 'Access-Control-Allow-Origin' header is present on the requested resource.' in Chrome Dev tool. Please let me know if I'm missing something. – user1330974 Sep 03 '16 at 13:14
  • But, I think that is server side matter. – Oki Erie Rinaldi Sep 04 '16 at 09:01