I made a website with ReactJS which monitors an online database real time, and allows deletion of items therein. The data source is from a .NET server that I wrote previously, which provides an API for the ReactJS website to fetch. I thought the world would be as peaceful as the stream of data flowing over the internet and arrive at my browser, until the day when CORS error came up into my console. I thought it is time to rise up against challenges. Warriors grab your keyboard and favorite IDE, and Let’s begin the journey. If you are a desperate problem-solver and your service is down because of that, you can scroll down to the take-away section to get a condensed answer and bookmark this page for future reference or for further understanding of the CORS topic. You will also find much more contents linked with each other with my other technical “how to” blogs.
I have set up a .NET server which fetches data from a database, and provides an API for deleting individual entries. The API is defined as follows:
- http://localhost:44300/data/getdatatable is mapped to
DataController and its
GetDataTable action, which returns a json for the frontend to render
- http://localhost:44300/data/deleteid is mapped to
DataController and its
DeleteID action, which deletes the entry in the database matching the provided ID.
The implementation of API is like the following. To be concise, I only excerpted relative code snippets:
There is nothing appearing in my table. In such cases the first thing to do is to press
Ctrl+Shift+c, call out console.
Here comes CORRRRS!
— adding CORS header to .NET server
The error says “No ‘Access-Control-Allow-Origin’ header is present on the requested resource”.
So accordingly, we need to add the corresponding header to the resource, which means making the server to return a header with Access-Control-Allow-Origin. After I searched online for quite a while and tried out all null solutions, here is what the solution should be:
I added that middle line of code to the controller and it made everything work properly.
In some references, they recomment adding proxy option to the
package.json file in ReactJS repo. I tried that, and it works if the website is a local one, but it failes when the source is remote.
After the fix, the table is displayed nicely:
OK. Now let’s test our deletion button!
As expected, it pops up a confimation box, and we hit “OK” to confim the operation. Then the deletion failed. To figure out why, we brough back out best friend, the console:
The first thing we tried is to do exactly what we did last time, but unfortunately is does not work here any more.
As we can see in the .NET code for controllers, the
DeleteID function expects a string from the body of request. And here we have added the Access-Control-Allow-Origin header.
A preflight request is a small request that is sent by the browser before the actual request. It contains information like which HTTP method is used, as well as if any custom HTTP headers are present. The preflight gives the server a chance to examine what the actual request will look like before it’s made. The server can then indicate whether the browser should send the actual request, or return an error to the client without sending the request.
Because we have to provide to .NET API some infomationin in the body section specifying what to delete, we triggered the preflight check of server, consequently getting a CORS error.
And plus, the body content did not get into the controller input properly.
In theory, certain types of requests, such as
put, need to ask for the server’s permission before making the actual request. The browser asks for permissions by using what is called a preflight request. But clearly the server rejects such request.
The road of attack is like this: It is true that we are performing deletion operation, but since delete method will trigger preflight, and preflight is going to reject the request, we have to avoid the preflight, therefore avoid using delete method. We will use post method and avoid preflight in order to get our data. I show the code here first and will explain later.
Please do correct me if this is not a recommended practice. But this method works out of other practices.
The body of the posted message, instead of putting a string or Json object in there, need needs to be of type
FormData. In this way, the contents of form data, stored as key-value pairs, will smoothly flow into the corresponding controller and argument.
And, that’s it! our website is functioning perfectly. The dragon wailed and fell behind a distant mountain. “It may not come back to me”, I wrote in my diary, “but maybe still showing up in front of people to the other side of the mountain”.
when you get CORS error:
- If you want to access data from server without any parameters send to it, you shall make sure you add “Access-Control-Allow-Origin” header to the controller of server and avoid headers or arbitrary data in body section of the
- If you want to send some parameters the server, you shall not only add “Access-Control-Allow-Origin” header to the controller, but also wrap your parameters in a
FormDataobject with keys aligned to the input parameter names of the controller.
package.jsonfile works only if both server and frontend is run locally, which is unlikely to be useful in real cases (think of why do you need a website to access data from server if you are operating on the server?).