Cross Origin Resource Sharing
Photo by Klara Kulikova on Unsplash

Cross Origin Resource Sharing

Getting CORS error in the Developer Console is something that every Frontend Developer has faced when he first started building stuff. Fixing these type of errors won't take you long if you have encountered these issues earlier. I still remember the first time when I had encountered a CORS error, and it took me a quite long just to understand what was wrong with my code. All I had to do was to install a library on my Backend Server to fix this error. Everyone who is reading this article must have heard about CORS, once in his/her life. But do you actually understand the very internals of this mechanism? And the reason behind using CORS? Well, I can assure you one thing that you would be able to explain CORS in the simplest possible way to anyone after reading this article.

Definition of CORS

CORS acronym for Cross Origin Resource Sharing, is basically a way to allow a server to let know a browser(i.e the client, which has a made a request to it for a resource), the domains or URLs(of the web pages) that are allowed to access the server's resources. HTTP headers are used for implementing CORS. Browsers use the fetch and XMLHTTPRequest APIs in order to restrict Cross Origin Requests .

Overview of a Request that demonstrates CORS

Let's suppose that you visit the website https://www.helloWorld.com and after the browser is done loading you have a web page on your screen. The only element present on this web page is a button which when clicked, fetches you the Top 10 most popular songs on Spotify. Now, in order to get this information from Spotify's Database, Spotify has created a Public API, which pulls this data from the Database when you make a POST request to it. So, when you click on the button on the web page, the Javascript code present in the web page, which has been listening to the onclick event for the button, makes a POST request to the Spotify's Public API and you expect to see a list of songs on your screen. But instead there's no change on the web page, it still has only one button, and no matter how many times you click that button you don't get the list of songs. When you open the Developer Console, you see something that looks like the below image

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:3000/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:3000/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.

Let https://localhost:300 = Spotify Public API

And this is what a simple CORS error looks like. Now, in order to understand what went wrong, we have look into each request that was sent and the response that was received when we clicked on the button.

HTML code for the Web Page.

<!DOCTYPE html>
<html lang="en">
? <head>
??? <meta charset="UTF-8" />
??? <meta http-equiv="X-UA-Compatible" content="IE=edge" />
??? <meta name="viewport" content="width=device-width, initial-scale=1.0" />
??? <title>Document</title>
? </head>
? <body>
??? <div>
????? <button id="btn">Click Me</button>
??? </div>

??? <script>
????? console.log("Hello");
????? let btn = document.getElementById("btn");
????? btn.addEventListener("click", fun);

????? async function fun() {
??????? const response = await fetch("https://localhost:3000", {
????????? method: "POST",
????????? headers: {
??????????? "Content-Type": "application/json",
????????? },
????????? body: JSON.stringify({ name: "Prashant Pandey" }),
??????? });
??????? console.log(response);
??????? const data = await response.json();
??????? console.log(data);
????? }
??? </script>
? </body>
</html>        

You can notice the script tag in the above code. The function fun is called when the button is clicked and then the fetch API is used to make a POST request to the Spotify's Server.

The typical Request, Response flow for our case would be that the browser send's a POST request like the one given below

POST /doc HTTP/1.1
Host: spotify.public.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: https://helloWorld.com/index.html
Content-Length: 55
Origin: https://helloWorld.com
Pragma: no-cache
Cache-Control: no-cache1        

And it receives a response like the one given below from the server

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://helloWorld.com
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain        

You don't have to go in detail about what each line in the above snippet means. The important one's would be explained below.

But this is not how things go around. Let's see what happens.

When the button is clicked, the Web Browser straightaway does not make a POST request to the Spotify's Server. Before making the POST request, it make an OPTIONS request to the API, which would look something like below

OPTIONS /topSongs HTTP/1.1
Host: spotify.public.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://helloWorld.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type        

The question arises that what is an OPTIONS request, why does the browser makes this extra OPTIONS request, and what does all those fields in the above request mean?

First of all, an OPTIONS request is made by a client when it wants to get some information about the server from the server itself.

Well, what information does the browser want to know about the Spotify's Server in this case?

This is where CORS comes in, as I had mentioned earlier that CORS is a mechanism to let know a browser the domains and URL of the websites or web pages which can fetch resources from it. So, here the Browser wants to ask the Spotify Server if the web page https://helloWorld/topSongs page can fetch the Top 10 Popular Songs from it. And this is why it makes the OPTIONS request before making the POST request.

Now for the header fields in the OPTIONS request. The fields that you would find different from a normal POST or GET request are the Access-Control-Request-Method and the Access-Control-Request-Headers.

The Access-Control-Request-Method is the header which tells the Server the type of request it wants to send to it, in our case a POST request. The Access-Control-Request-Headers tells the server the headers that would be included in the request that it wants to send, in our case the POST request would contain X-PINGOTHER and Content-Type headers.

The request has the Origin and the Host field. Origin gives the URL or domain of the Website which is asking the browser to make the request to the Server(in our case helloWorld.com). The Host field gives the URL of the Server, in our case the Spotify Server(spotify.public.com).

The response that the browser would receive from the Server is given below

HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive        

The above response has 4 headers that is important to us.

Access-Control-Allow-Origin -> This header mentions the URL or domain of the website which can access the server's resources.

Access-Control-Allow-Methods -> This header mentions the type of Requests that the website can make.

Access-Control-Allow-Headers -> This header mentions the headers which are allowed to be sent with the Requests.

Access-Control-Max-Age -> This header mentions the time for the information provided by this response is valid or the time after which the Browser needs to make an OPTIONS request to the server.

If the response of the OPTIONS request from the server contains the Origin, Methods and the Header that the browser needs to send then and only then the browser moves forward to make the request which it had to make, in our case the POST request to fetch the Top 10 Songs.

As you can see in the response from the server that the domain which is allowed to make request to the server for resources is https://foo.example and not https://helloWorld.com and that is why we were receiving the CORS error in our Developer Console.

So, what would the response for the OPTIONS request look like if Spotify wanted all the websites on the internet to have access to it's resources??

Then the Access-Control-Allow-Origin header would have an asterisk(*) as it's value instead of any particular domain.

HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alivet        

So, a Backend Developer can add the Access-Control header to every response to restrict websites from consuming it's data.

Ending Note

In the end CORS proved to be nothing more than a concept of a response header which allows sharing of data between a server and a web page.

Sharing resource between two different origins(Server and Browser).

I hope this article was helpful, do share your views on this in the Comment Section below.

Jay Kant Adjariya

Senior Software Engineer at OnePint.ai | Ex-Nextuple | B.tech at IIIT Bhopal

2 年

Very Informative ??

Aastha Goyal

GSDE @ TESCO || Ex-SDE Intern @ Insane AI || Extern @ CommVault || Pratidhi Mentee @ CommVault || IIIT Bhopal'23

2 年

Great work!!

要查看或添加评论,请登录

Prashant Pandey的更多文章

  • Similarities between the Architectures of Node.js and NginX

    Similarities between the Architectures of Node.js and NginX

    In this article, I'll try to explain the similarities between the Architectures of NginX and Node.js, in the easiest…

    4 条评论
  • gRPC vs REST

    gRPC vs REST

    Every developer must have heard about REST in his/her life. REST stands for REpresentational State Transfer.

  • What is QUIC and is it really?quick?

    What is QUIC and is it really?quick?

    If you have never heard of the word QUIC and you are a developer, whose work is somehow related to the fascinating…

    4 条评论
  • What exactly are UUIDs and how are they so?Unique?

    What exactly are UUIDs and how are they so?Unique?

    If you have ever worked with any kind of database, be it SQL or NoSQL, in your life, then you must have come across…

    2 条评论
  • How http became the https that we know today?

    How http became the https that we know today?

    The only difference that one can notice between http and https by just looking at the words is the letter s, but this…

社区洞察

其他会员也浏览了