Cross Domain error - i thought i'm using jsonp (?) so what's wrong

Hey guys,
Dev Tools show me 2 errors. I suppose it’s because of a cross domain ajax request?
1.
jquery.min.js:2 Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "https://codepen.io" from accessing a frame with origin "https://s.codepen.io". Protocols, domains, and ports must match.

  1. You can see that i search for “Ronaldinho”, so the link is properly made.

    XMLHttpRequest cannot load https://en.wikipedia.org/w/api.php?action=query&format=json&generator=searc…explaintext&exsentences=1&exlimit=max&gsrsearch=Ronaldinho&callback=JSON_CALLBACK. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://s.codepen.io' is therefore not allowed access.

I thought that when i end the URL with a callback, it’s automatically jsonp, so i don’t know why i get that kind of error. How to fix it?

Thanks for any advice ! :slight_smile:

Try using just http instead of https

Unfortunately didn’t work. I thought it might be this reason too, but it’s not :confused:

I am with stuck with the same project, the API request is not passing successfully. Do we have to create an account or something?

I just wanted to let you know that i found the solution with the help of other Campers :slight_smile:

What surprised me, was that i didn’t need to add a prefix “https://crossorigin.me/”, to the link. I’ve seen some posts that this is the only way to get around cross origin issues on codepen, but it works without it.

The only thing that worries me, is that i wasn’t able to make it work with $.getJSON. I still don’t know why.

This is the code that worked:

   $.ajax({
          url: mainLink,
          type: "GET",
          dataType: "jsonp",
          success: function (data) {
      console.log(data); 
// and other stuff i do with the data i get 
  }, 
          xhrFields: {
        withCredentials: false
      } 
        }) // end ajax
1 Like

The reason it worked is that you are using JSONP, which is quite different from normal JavaScript Ajax calls (JavaScript XMLHttpRequest object).


A brief explanation (somewhat technical):


Even though jQuery uses the $.ajax notation, this is not really an Ajax call. It is JSONP (when the datatype property is set to JSONP).

The way JSONP works is that it dynamically adds a < script > tag into the header of your HTML file.
When your dynamically generated script tag (by jQuery) is executed by your browser, it returns a script from the src url - which contains a call to your callback function (whose name is also generated internally by jQuery if it is an anonymous function).

So the behavior seems asynchronous. BUT this asynchronous behavior is because of the way the browser dynamically loads scripts, and has nothing to do with REST APIs or JavaScript AJAX requests. In fact, JSONP is not even an Ajax request (i.e. XMLHttpRequest).

Limitations of JSONP:

  1. Only GET requests are allowed
  2. JSONP has to be supported by the source server (much like CORS). Fortunately, most websites/server configurations support JSONP (partly because of the limitations of CORS, and partly because it is an older technology compared to CORS)
  3. Because JSONP is not an AJAX request, you cannot make synchronous requests. The Asynchronous behavior is the result of your browser processing the script tag in the HTML page (as explained above)
  4. Security risk: The website/server returns a script. So essentially, you are trusting an external server to send over JavaScript code that could potentially read anything your browser client has access to (for e.g. cookies, other data on your current webpage like usernames, emails, etc. etc.). Hence it is safer to go with reputed sites if you are using JSONP.

Limitations of CORS (because of which we have to use JSONP or a CORS Proxy):

  1. Most websites/servers do not support CORS - even though this is a newer, superior, and safer technology. The reasons are many. CORS depends on certain headers to be present in your GET/POST/etc. request. A lot of corporate firewalls and internal networks strip these headers before the call goes out. So the receiving server never gets these headers - without which CORS requests cannot work.
  2. CORS on the client side: OLD browsers do not have any support for CORS (though there are work-arounds). All newer browsers automatically support CORS.
  3. CORS on the server side: CORS has to be enabled on the server side. If the server that responds to your Api call does not have CORS, there is nothing you can do about it on the client side that will make a CORS request work (workaround: Use a CORS Proxy). When the server does not support CORS, you will get this message: “No ‘Access-Control-Allow-Origin’ header is present on the requested resource”

There are a number of ways to get around the CORS/Ajax Request not working problem:

  1. Use a CORS Proxy: These are proxy servers that funnel the request on your behalf. You can create a proxy server on your local machine (for testing purposes) with NodeJS ( https://www.npmjs.com/package/json-proxy), PHP & Apache Server, Ruby on Rails, etc.
  2. Use publicly available CORS Proxy servers: eg. https://jsonp.afeld.me/, https://crossorigin.me/, http://cors.io/, etc.
  3. Use JSONP :slight_smile:
  4. Using iFrame: this is another solution, but it has all the disadvantages of iFrames - slow performance, clunky, communication between the iFrame and your page, etc.

I did not know any of the above a month ago. While working on the “Random Quotes Machine” project, I did a lot of research into all this (it took me 50 hours to complete that single project :slight_frown:). But I learned a lot in the process. :smiley:

Hope what I have learnt helps you and others.

  • Jay
36 Likes

Great explanation!
Thanks jaytsecan.

Can u check this?

I found here for script tag method u mention

The way JSONP works is that it dynamically adds a < script >


This:

A Possible Workaround
Luckily, not everything is affected by the same-origin policy. For example, it is quite possible to load an image or a script from a different domain into your page—this is exactly what you are doing when you include jQuery (for example) from a CDN.

This means that we are able to create a tag, set the src attribute to that of our JSON file and inject it into the page.

var script = $("<script />", {
    src: "http://run.plnkr.co/plunks/v8xyYN64V4nqCshgjKms/data-1.json",
    type: "application/json"
  }
);

$("head").append(script);

Although that works, it doesn’t help us much, as we have no way of getting at the data it contains.


So here they being say that data cant be extracted from script tag?


Also i tried with POST req jsonp and it works
Here u mention this:

Limitations of JSONP:

Only GET requests are allowed

But here this:
Limitations of CORS

…CORS depends on certain headers to be present in your GET/POST/etc. request…

So does this headers in ‘limitation of jsonp’ refer to headers in req when we send to server, and in this second ‘limitation of cors’ headers refers to headers of req that server send us as response?

Does server have this verbs get, post etc. when he send us, and why?

Also i read also somewhere that jsonp can go only with GET req…

These are separate issues.

(1) [quote=“nameToReachPeople, post:8, topic:11012”]
This means that we are able to create a tag, set the src attribute to that of our JSON file and inject it into the page.

var script = $("<script />", {
src: “http://run.plnkr.co/plunks/v8xyYN64V4nqCshgjKms/data-1.json”,
type: “application/json”
}
);

$(“head”).append(script);

Although that works, it doesn’t help us much, as we have no way of getting at the data it contains.https://www.sitepoint.com/jsonp-examples/
[/quote]

What the above code snippet is talking about is gettinig a json “file”, not a script. What we need is a script to execute that will call our callback function. Trying to get a static file (as the above code snippet showed), no matter the format (json, xml, etc) will not work.

(2) I think you may be getting confused between the different concepts. GET/POST/etc HTTP verbs are part of the HTTP protocol (they are independent of headers). Headers on the other hand are properties (or name/value pairs) that are sent on every HTTP message both from the client to the server (request) and from the server to the client (response). They are 2 separate concepts.[quote=“nameToReachPeople, post:8, topic:11012”]
So does this headers in ‘limitation of jsonp’
[/quote]

Headers have nothing to do with the limitations of JSONP. The limitation is with the HTTP method. JSONP is (or should be) a read-only request (which means that you can pass parameters to the request and get a response, but you should NOT be able to change the state of the server with a JSONP request).

According to the HTTP specification, POST/PUT/DELETE allow you to CREATE/UPDATE/DELETE a resource on the server. Hence, these HTTP methods should not be allowed with JSONP (I have seen incorrect implementations of RESTful services where a GET request changes the state on the server - but this is a violation of the GET HTTP specification and is strongly discouraged). Sometimes people use a POST request as a read-only request instead of using it to CREATE a resource (for various legitimate reasons - especially security)

Some helpful (though technically in-depth) references to explain the above concepts:

(1) The HTTP 1.1 specification (has info about headers in requests and responses, different HTTP methods (GET/POST, etc) and more https://www.w3.org/Protocols/rfc2616/rfc2616.txt
(2) REST (REpresentational State Transfer) is an architectural style, and an
approach to communications that is often used in the development of Web services (https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm)

2 Likes

To further clarify the difference between JSONP and CORS:

CORS:

  1. requires support on BOTH the client side and the server side
  2. makes use of headers in the client request. The resource on the server being requested MUST have the appropriate CORS permissions for it to be served to the client.

JSONP:

  1. requires support ONLY on the server side.
  2. When making a JSONP call (through JavaScript or jQuery) one is not explicitly using any HTTP verbs (like GET/POST/PUT/DELETE, etc). You are simply requesting a script (with the src tag) just like you would be requesting a javascript library, css stylesheet, etc. (the browser uses GET requests by default in these cases)
    Since JSONP puts the script in the < head > section of your HTML file, when the javascript engine of your browser parses the changes to the HTML page, it requests the script from the internet and executes it (just like it executes any other < src > script attribute) before doing anything else.
    Once the script has been executed (i.e. your callback function called), it continues processing whatever comes next.
3 Likes

Hey Hey… You can use $.getJSON just add &callback=? to the end of your url, jQuery will handle the rest of the stuff…

$.getJSON('https://en.wikipedia.org/w/api.php?action=opensearch&format=json&search=chad&namespace=0&limit=50&callback=?', function(data){ console.log(data); });

1 Like

Dear jaytsecan,

Thank you very very much for your explanations. I hope you will find the time to read this message where I complain even more that I ask.

I have read a lot about these issues, however for lack of time or focus, I do not get to understand how to make even the simplest requests. It is beyond me why there is such lack of good explanations. It is a must in our learning process but really, really bad explained. For us using CodePen in Fcc it looks to get even trickier, because CodePen explanations are not such, or maybe only for people that already know. Could please help me with the following:

  1. My first questions is how can I access and download a .json .js .php .txt file with JS on a remote server? (no JQuery, please)? I am talking about files that can be viewed by anyone with their browser. If I am not mistaken the easiest way would be to use the same route we use for images and scripts, with the src attribute. In a previous response you said “Trying to get a static file (as the above code snippet showed), no matter the format (json, xml, etc) will not work.”… Could you, please, explain why can´t we access the data if we do have access to the file?

  2. If I can have access to the data through … why don´t they teach us that? What is the advantage in getting into a JQuery JsonGET methods and callbacks when we even a have not the first clue on what is a XMLHttpRequest? It is amazing and discouraging the amount of hours that I loose getting lost and having to go back to learn the basics just because some people rather teach bootstrap, JQuery and frameworks before the language itself.

  3. In our case, students of FCC using CodePen, I would assume that the CORS limitation cames from the CodePen server which would not allow requests to third party servers through its own. However I find that from CodePen I can access a given file on a server with a XMLHttpRequest (https://mathiasbynens.be/demo/ip.php), but cannot access it if I host the same file on my own server(http://abanoa.dscloud.me/000-RECURSOS/Datos%20locales/ip.php). Any clue why this happens?

Thank you!!

PS. Just to clarify. I am not interested in accessing data though APIs such as google maps and weather apis. That will come. I just want to be able to gather small but complete data files and do my own filtering locally.

A link to your post just saved me countless more hours of work. My calls work now! Thank you for adding this tool to my box!

Jay, that’s a wonderfully clear and thorough response. Do you remember the sources where you read that stuff? I’m having similar problems with the local weather app, and I’d like to learn more about how to identify and work around cross-origin problems.

Thanks,
CKB

This needs to in a FAQ, or a sticky or even in the course content! Thank you @jaytsecan for your research and your time! I am on the wikipedia viewer project and have run into this very problem, so with this I can now progress!

I had success with specifying an origin through Wikipedia’s API Sandbox.

On the first page of it under main you can check the box for origin and then specify your origin as *.

Their documentation for the “origin” URL parameter reads –

For non-authenticated requests, specify the value *. This will cause the Access-Control-Allow-Origin header to be set, but Access-Control-Allow-Credentials will be false and all user-specific data will be restricted.

This totally solved the issue for me. You won’t have access to user-specific data, but we don’t need it for the scope of this project anyway.

If you’d rather do it through the URL and not use Wikipedia’s API Sandbox, you can just add &origin=* somewhere in your query URL.

I hope it helps someone! :+1:

Here’s a screenshot of what it looks like in the Sandbox –

3 Likes

You are the man! This was the tip that solved my CORS issue. Thanks a lot!

Here’s the URL I ended up using:

https://en.wikipedia.org/w/api.php?action=query&format=json&origin=*&list=search&srsearch=[search term]

2 Likes