Cross-Domain Calls. Why sometimes needs &callback=?

This is a topic that actually needs quite a bit of explanation. The shortest answer I can give is that when your browser downloads resources for a web site/app, it keeps track of where they were downloaded from. We this the site’s origin. JavaScript code that was downloaded from one origin is prevented from making requests to other origins by default. So, when users go to your site to download your Wikipedia app, the origin gets stored as https://marcosperswikipediaapp.com. Your app needs to reach out to the wikimedia API for data, but that API is at a different origin. Without any special configuration, your browser prevents this request. This is call the same origin policy, and it’s vital for keeping you safe.

Why? Imagine you just went to your bank’s page to check your balance. You log in, which stores an authentication token in your browser so you don’t have to log in again. When you’re done, you close the site, but forgot to log out. Even though you’re not at your bank’s site, your auth token is still stored and ready to be sent with the next request to your bank’s URL. A few minutes after your online bank visit, you get a link to some site you’ve never heard of that promises the best prices on Girl Scout cookies anywhere. We’re talking samoas, grasshoppers - all the good stuff at just dollars per pound. You’re only human, so you click the link. The site it takes you to has pictures of girl scout cookies, but after looking around for a while, you see that shipping will take 4-6 weeks, so you’ll just go to the store and buy some from the girls out front. What you did not see was that the site also ran some JavaScript that made requests to your bank that transferred money from your account to another, probably not a Girl Scout’s. In a world without the same origin policy, you’re boned. The requests go through and the money is transferred. With the same origin policy, however, your browser stops the request because your bank’s servers haven’t allowed http://discountshortbread.com. Saved!

While this is good protection, it makes life more difficult for us programmers who just want to get data about the weather or a nice quote. The old solution is to this problem is called JSONP, or JSON with Padding. You see, JavaScript is not allowed to make cross-origin requests, but HTML is. So if we use JavaScript to create a script tag and then give that tag the URL of the data we want, we can retrieve data no problem.

<script src="https://somesite.url"></script>

This is safe because you can only make GET requests this way, so it’s not like people can make changes to your bank account. How do we use the data, though?

Well, we know that we can pass data as an argument to a function:

someFunction({ name: "Dale", occupation: "Pest Control"});

And we know that if we define a function in the global scope, we can call it from any other script:

<script>
    function someFunction(data) {
        console.log(data);
    }
</script>
<script>
    someFunction({name: "Hank", occupation: "Propane and propane accessories" });
</script>

So what if we defined a function before we sent our request, then had the data come back wrapped in a function call? We do this by sending the function’s name in a query parameter - callback=someFunction

<script>
    function someFunction(data) {
        console.log(data);
    }
</script>
<script src="https://some.url?callback=someFunction"></script>

The response will be a script that just runs the function with the data in it:

someFunction({name: "Peggy", occupation: "Substitute teacher" });

That’s the reason you do need the param. The reason you don’t need the param for other requests is because there’s a newer way to handle cross origin requests. We can tell the server that it’s OK to accept requests from certain (or all) origins. It’s as simple as adding a few headers in the server’s code. This is called CORS, and it’s simple enough that it’s hardly worth mentioning.

3 Likes