1
votes

So I have a small angular app which connects to my node api. I don't have a problem with my get request, I get the data from my api on load. My post request throws an error tho;

Access to XMLHttpRequest at 'http://localhost:3000/api/heroes' from origin 'http://localhost:4200' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.

and

ERROR HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "http://localhost:3000/api/heroes", ok: false, …}

This is my post method @ client side;

addHero(hero: Hero) { 
    this.http.post<Hero>("http://localhost:3000/api/heroes", hero)
        .subscribe((responseData) => {
            console.log(responseData);
        })
    this.heroes.push(hero); //Adds new hero to original array
    this.heroesUpdated.next([...this.heroes]); //Adds new array to subject
}

and here's my backend;

app.use((req,res,next) => {
res.setHeader("Access-Control-Allow-Origin", "localhost"); 
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 
res.setHeader("Access-Control-Allow-Methods","GET, POST, PATCH, DELETE, OPTIONS");
next();
})

app.post("/api/heroes", (req, res,next) => {
const post = req.body;
console.log(post);
res.status(201).json({message:"Succeed"});
});

So I've allowed content-type but I'm still getting the error. Any suggestions how to move on from here?

1

1 Answers

1
votes

You correctly understand that the issue lies with CORS.

Your error is: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.

In some circumstances the client will send a "preflight request" to the server. When?

For example, when your content type is "complex". Complex means not in application/x-www-form-urlencoded, multipart/form-data or text/plain.

Or when you are sending a POST request with a body.

There are other occasions too, you can read more about this on MDN.

The preflight request is just a request with method "OPTIONS" that goes to the very same endpoint. It expects to receive back a

  1. successful response

  2. that allows all headers

  3. and allows the origin.

Your express middleware app.use((req,res,next) => {... ticks the requirements 2 and 3. (Actually for the 3 I would recommend setting "Access-Control-Allow-Origin" header to http://localhost:4200 instead of just localhost)

But you have no middleware or route handler to handle the OPTIONS request. Let's add one:

If we get an OPTIONS request, we return a 200 OK. If it's not an OPTIONS request, go to next handler.

app.use((req, res) => {
    if (req.method === 'OPTIONS') {
        return res.sendStatus(200);
    }
    next();
});

Since we want the OPTIONS response to ALSO set the right headers, we must include it after the "cors middleware":

app.use((req,res,next) => {
// set cors headers and call next()
});

app.use((req, res, next) => {
// handle preflight requests
});

app.post('api/heroes', ...)

Finally, there are of course ready solutions for this, for example the cors package on npm that provides a middleware for express. Check how to use it on its npm page.