I faced the CORS error every time I create a
new project. But this problem only occurs in some particular cases. the CORS error means Cross
Origin Resources Sharing error. But this error only happens in the browsers. If I request
my backend from a terminal or from Postman, I won't see the error. It only happens in browsers
because they have some security conditions. If the frontend tries to access a backend which doesn't
have the same URL, the browser throws an error. Cross Origin Resources Sharing means that the
frontend and the backend are at different URLs, at different Origins. And there is no information
about letting them share resources. Because what if a hacker copy a website and use the same
backend? The frontend will be a different URL, but the website will consume the same backend.
When I try to access my personal account, I won't notice anything strange, as the data is
all good. Meanwhile, the website will steal my personal account. This is why the backend must
identify the trusted frontends. To solve this, there are some HTTP headers which tell the
browser that the frontend and the backend work together. Those headers are Access Control
Allow Origin, Access Control Request Method, Access Control Request Headers. Those are headers
sent by my backend to tell the browser how to protect the user. The first header tells the
browser which frontend can request the backend. But this one alone is not enough. The second
header tells the browser which HTTP method is accepted by the backend. And the last header tells
which headers are accepted by my backend. In fact, the browser will perform a first request to
check if the backend is okay with the current frontend. This is called the pre-flight request.
And it's done with the Options HTTP method. The pre-flight request is a request done automatically
by the browser. This is why I don't see it from a terminal or from Postman. So, the CORS error
can only be solved by configuring my backend to accept a frontend with a different origin.
Let's see how. Let's start by creating a new Spring Boot project. Because, as said,
this always happens with new projects. I set the package. I choose Maven. I set
the artifact name, and the project name. I will only add the web dependency. Because the
problem is visible in the most simple Spring Boot application. Let's download it and open it with
IntelliJ. I will start by creating a controller. Let's create the controllers package,
and my controller, greetings. It will be a rest controller.
With a get endpoint, greetings. And return a DTO. Let's create the DTO as a record in the DTOs
package. And it only contains one field. And now return the content. "hello" Let's start my application and test this endpoint. curl localhost 8080 greetings. I can request
the endpoint without any problem. I got the response. Everything is okay. I can even
test it from Postman. localhost 8080 and send. Everything is okay
too. As a backend developer, I won't go any further. I've tested my application
from a terminal and from Postman. And everything goes fine. So it's time to push to production.
But what happens when the frontend access this endpoint? Let's create an Angular project. NG new
frontend. Let's pick the default rooting and CSS. I won't create any new component.
Just a simple paragraph in the main component and request the backend. Let's first remove all the HTML content. Add
a title, message received from the backend. And in the paragraph, I will put a variable
that I will create in my component. In the Typescript component, let's
first import the HTTP client. The response variable. In the
constructor, inject the HTTP client. And now, in the initialization of the
component, I will request the backend. Get, BackendContent, I will
create this interface later. The endpoint now, localhost 8080
greetings, and subscribe to the response. I will save in the variable
the response from my backend. Let's now create the backend content. It's just an interface. With the field content. Let's import the backend content. And import the HTTP module. Ok, I have my Angular application which requests my backend, and simply
displays the response. Let's test both together. Let's first go into the frontend folder, NG serve to start my frontend. And
now in the browser, I see the empty. Here I can see that the greetings endpoint
responds with an error. If I look carefully I see that the request wasn't even sent. It's a
pre-flight request. The same happens with other browsers. But at the beginning I've said
that this only happens when the frontend and the backend are at different Origins.
Let's see what happens when both are at the same origin. Both the frontend and the backend
at the same origin means that both are served by the same web server. So I must include the
frontend inside my backend. But I can't do this with Angular. So I will just create a simple
HTML page with an Ajax request to my backend. Let's first go to the resources folder. Into
the static I will create the index.html. I create a title and a paragraph. Now at the beginning, I will insert the
JavaScript. I will add an event listener. to know when the content is loaded. When loaded, I will execute this function. Instantiate xhr, which allows
me to perform Ajax requests. Response type is the Json. And when loaded, I will call this function. If the request is done correctly, I will replace the paragraph content with the content of the response. Let's open the Ajax request with a get to
the greetings endpoint. And make the call. Now create an endpoint to deserve this content. Let's create another controller. Now this time is
not a rest controller but just a plain controller. It will return a string which is just the
path of the index HTML file. Let's test this. With this configuration, everything goes fine.
Because the frontend is at the localhost 8080 and the backend is at localhost 8080. But as
said, I can't do that with Angular. I have to configure my backend to accept a frontend
from a different origin. Let's see a quick fix. Let's add the CrossOrigin annotation. And with the
origins, http localhost 4200. Let's test again. Now it works. But I have to include the
CrossOrigin annotation at all the endpoints. This is not suitable. So I have to create a
global configuration. Let's first comment this annotation. And now create another package,
config. I will put the configuration in a class named WebConfig. Add the configuration
annotation. And the bean, WebMVCConfigurer. I will just implement the add CORS method. Registry, add the mapping to all the routes. Allow the origin of the frontend URL. Add some accepted methods. get post and delete. And now add some accepted headers. content type and authorization. Notice that this
method accepts a list of strings, a list of URLs. This means that
I can put all the frontends, from all the environments of my application,
and the localhost address too. Let's test again. It still works. And it will work for any new
endpoint I create in my backend. This is a typical error, and it has a simple solution on
the backend side. I hope you find this video useful. Before leaving click on the like button,
subscribe to my channel and see you soon. Bye!