2

In my angular2 app, I tried to make a cross domain ajax call. Although the call went through successfully, on angular2 side, the error callback was always triggered instead of the success callback. Here is the code:

this.http.post('http://localhost:3000/tasks/add', '["' + task + '"]', {headers: headers}).subscribe(
        data => null,
        err => alert("err"),
        () => alert("succ")
    );

In the browser console I saw this:

XMLHttpRequest cannot load http://localhost:3000/tasks/add. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

The server side was implemented in nodejs and it included the following to handle preflight

router.options('/add', (req, res, next) => {
    console.log('!OPTIONS');
    var headers = {};
    // IE8 does not allow domains to be specified, just the *
    // headers["Access-Control-Allow-Origin"] = req.headers.origin;
    headers["Access-Control-Allow-Origin"] = "*";
    headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, OPTIONS";
    headers["Access-Control-Allow-Credentials"] = false;
    headers["Access-Control-Max-Age"] = '86400'; // 24 hours
    headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept";
    res.writeHead(200, headers);
    res.end();
});

The above server code was successfully executed, and client side did send the post request after the preflight options request.

My question is, what can I do in angular2 to make it trigger the success callback, which it should?

Update:

I am attaching a screenshot here and it was took in Chrome. The bottom part of it shows CORS error message, but top portion shows that the request went okay with 200. As a matter of fact it did go through, as I received both the options and post requests on the server side.

enter image description here

Update 2:

Tried express-cors on nodejs (server) side, still the same. (My initial code already handles preflight options request - the code can be found above in the original portion of this post. Unless there was a mistake in my original nodejs code, express-cors was not expected to change anything.)

Below is the code I tried with express-cors, basically the same as what's on its npm page:

var express = require('express');
var cors = require('express-cors')

var router = express.Router();
router.use(cors({
    allowedOrigins: [
        '*'
    ]
}))

Update 3:

Mystery solved! In my original code I only set the CORS headers in the options response, but not the response to the post request followed the options request. That appeared to still allow the whole process to complete at the application level - since the server side did get the post request and processed the data, but angular saw an error since the response did not include the proper headers. I modified my code to not only send back CORS headers in the options response, but also the post response, and now angular triggers the success callback.

Peter Pei Guo
  • 7,770
  • 18
  • 35
  • 54
  • For Update 3, so you didn't need any Angular2 preflight CORS options send, just to return CORS in the header on the POST response from Express? I'm having trouble with this today, and I'm sure I'm missing something. I'm using ASP.NET MVC as the API Server and have `[EnableCors(origins: "*", headers: "*", methods: "*")]` on my controller, but I'm still getting the error like you had in your screenshot. – Eric D. Johnson Feb 19 '16 at 21:21
  • Did you also call config.EnableCors(); in your register method? – Peter Pei Guo Feb 19 '16 at 21:30
  • in `App_Start/WebApiConfig.cs` I indeed have `config.EnableCors();` in the Register method, right at the top. – Eric D. Johnson Feb 19 '16 at 21:47
  • So based on http://stackoverflow.com/a/22968724/3018212 "The preflight is being triggered by your Content-Type of 'application/json'". So I should be set on the preflight client side, which makes sense with your response. Hmm – Eric D. Johnson Feb 22 '16 at 14:00

2 Answers2

0

Your error message doesn't look like the preflight request was successful. The preflight request is made by the browsers automatically before the actual request, if the preflight request results in an error, like in your case, the actual request isn't made at all.

Try this on the server instead:

 headers["Access-Control-Allow-Origin"] = "http://localhost";
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Thanks! According to nodejs log, it did receive the actual post request after options. It seems like the preflight was successful, otherwise it won't send the post request. The data was also inserted to the database, so the operation was successful. That's why it is odd to see the error callback being triggered on the client side. Currently the server responds to preflight with allowed origin set to *, which should cover localhost. I will try what you have suggested, instead of *, I will specifically set it to localhost. I will let you know. – Peter Pei Guo Dec 31 '15 at 13:30
  • Tried and did not work. I updated my post with a screenshot took in chrome. – Peter Pei Guo Dec 31 '15 at 17:28
0

In fact, there is a dedicated module for CORS with Express called cors. You can install it like this: npm install cors.

That said, there is nothing to do in the browser since everything is done under the hood for cross domain requests:

  • The browser sends the Origin header
  • Use simple or preflighted requests
  • Check the CORS response headers to see if your request can be executed

This link could help you to understand how CORS works within browsers: http://restlet.com/blog/2015/12/15/understanding-and-using-cors/

So in short, it's a server issue not something in the Angular application. You can check the response content (headers) in the Chrome dev tools, tab Network to see that CORS headers are there in the response (both simple and preflighted).

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • I will try that cors module and let you know. Thanks! What seemed to be puzzling is that the server did receive the actual post request following the options request, which indicates that it went fine. Also the post request was meant to insert some data to database and the data was inserted, all those indicated that cors was completed successfully. That is why it is odd that the error callback was triggered in angular. – Peter Pei Guo Dec 31 '15 at 13:38
  • Tried and did not work. I added the code to my OP as "update 2". – Peter Pei Guo Dec 31 '15 at 17:56
  • 1
    I had a look at your screenshot but I can't see the `Access-Control-Allow-Origin` header in the response headers of your POST request. That's the problem in fact... – Thierry Templier Dec 31 '15 at 18:19
  • Good catch! Mystery solved. I added "update 3" to my post and included this information. Thanks! – Peter Pei Guo Dec 31 '15 at 18:37