Angular CORS request blocked
In case you are using angular-cli, you can use a proxy:
proxy.conf.json:
{
"/api": {
"target": "http://localhost:8888",
"secure": false
}
}
Will redirect all requests with /api
prefix to localhost:8888 without any cors issue.
Offical docs: https://angular.io/guide/build#proxying-to-a-backend-server
Firstly, the problem on the client was due to the behavior of Firefox opting in to handle pre-flight CORS. Instead of using GET
method,OPTIONS
method was used. As it is evident from my code, I do not have any handler for handling OPTIONS
. After some googling, I came across this post on github: Express CORS middleware. Using this and making the following modifications to my client request headers, I was able to properly get it up and running. Here's the code:
CORS Middleware:
function myCors(req, res, nxt) {
res.header('Access-Control-Allow-Origin', 'http://localhost:4200');
res.header('Access-Control-Allow-Methods', 'GET,PUT,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Access-Control-Allow-Origin, Content-Type, Accept, Accept-Language, Origin, User-Agent');
if(req.method === 'OPTIONS') {
res.sendStatus(204);
}
else {
nxt();
}
}`
Mounting it to the app instance:
app.use(myCors);
On the Angular client side service:
this.corsHeaders = new HttpHeaders({
'Content-Type': 'application/json',
});
// ... adding it to the request
getContent(subs: Array<string>): Observable<IContent> {
return (() => {
return this.http.get<IContent>( (() => {
let r = this.root;
subs.forEach((s, i, a) => {
if(i === a.length-1) {
r += s;
}
else {
if(s !== '/') {
r += s;
}
}
});
return r;
})(), {
headers: this.corsHeaders
});
})();
}
Thanks everyone for their time and efforts.
Edit
Thanks to @neutrino for pointing out that adding the Access-Control-*
headers on the request makes no sense (and has no effect).
In development environment(localhost),you can do it easily without following any of these hard steps.You can simply download https://addons.mozilla.org/firefox/addon/cors-everywhere/ if you are using firefox and i think there must be an extension for chrome also.After downloading it will come to the firefox menubar and then you can click it to activate it,thats all you can now access to all apis as it automatically sends header with all requests.For production environment you have to configure it from your server by adding access-control-allow-origin to * (all)
If you're working with Angular CLI, NPM, Spring Data JPA and Tomcat 9, I finally found a solution to communicate between a frontend webapp (Angular) and backend webapp (Spring Data JPA) running on an application server (Tomcat).
In development environment:
The annotation @CrossOrigin("localhost:4200")
in your Spring DAO repository is just fine if you running ng serve
on default port 4200.
@CrossOrigin("http://localhost:4200")
public interface ConfigRepository extends JpaRepository<Config, String> {
}
In production environment:
If your application is running on a productive server, you have to modify your web.xml
and add a (e.g.) build-in CORS filter to allow access to other resources as the origin.
<!-- ==================== CORS Filter Definition ====================== -->
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Access-Control-Allow-Origin</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>Access-Control-Allow-Origin</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The difference to the template from Tomcat 9 CORS Filter is to add Access-Control-Allow-Origin
to cors.allowed.header
and set an actual allowed origin in cors.allowed.origins
e.g. http://localhost:8080
.
So, there is no need to specify explicit headers to an HTTP request. Thanks to @Neutrino.