15

When I call server without headers its working and server returns json:

this.http.get(url)

but when I add header:

var headers = new Headers({'x-id': '1'});
this.http.get(url, {'headers': headers})

browser returns error:

XMLHttpRequest cannot load http://domain/api/v1/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

I also tried add Origin header - browser error: Refused to set unsafe header "Origin"

And Access-Control-Allow-Origin header - no effect


On server (Laravel) I created middleware Cors.php:

<?php

namespace App\Http\Middleware;

use Closure;

class Cors {
    public function handle($request, Closure $next)
    {
        return $next($request)
            ->header('Access-Control-Allow-Origin', 'http://localhost:3000')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
            ->header('Access-Control-Allow-Headers', 'x-id');
    }
}

Im new to angular2 and CORS requests, dont know what to do.

  • Angular: 2.0.0-beta.0
  • Laravel: 5.0
  • Browser: Google Chrome
Shaddow
  • 3,175
  • 3
  • 22
  • 42
  • i think this problem in server properties see: http://stackoverflow.com/questions/36825429/angular-2-no-access-control-allow-origin-header-is-present-on-the-requested – Emir Mamashov Nov 07 '16 at 12:44

6 Answers6

7

A preflighted request with CORS means that an OPTIONS HTTP request is executed before the actual one. You switch from a simple request to the one since you add a custom header in the case of a GET method. This link could help you to understand what happens: http://restlet.com/blog/2015/12/15/understanding-and-using-cors/.

FYI the Origin header is automatically added by the browser when executing a cross domain request.

I think your problem is within the Access-Control-Allow-Origin header. You must set the host that makes the call and not the address of the server. You should have this instead (if your Angular2 application is running on localhost:8080):

return $next($request)
        ->header('Access-Control-Allow-Origin', 'http://localhost:8080')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
        ->header('Access-Control-Allow-Headers', 'x-id');

Hope it helps you, Thierry

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • my client is running on `http://localhost:3000/` and API server on `http://DOMAIN/api/v1/` ... When I add header to request, its change from simple to preflighted, which doesnt work and return error mentioned in question. – Shaddow Dec 22 '15 at 10:12
  • 1
    In fact, the content of the `Access-Control-Allow-Origin` header could be `*`. If you only want to allow your application regarding CORS, simply return what you get from the `Origin` header from the request... – Thierry Templier Dec 22 '15 at 10:30
6

I had the same issue in my Angular2 application. The problem, as already stated, is that before every request made by the client a preflight request is sent to the server.

This kind of request have a type OPTIONS, and it's duty of the server to send back a preflight response with status 200 and headers set for accepting requests from that client.

This is my solution (with express):

// Domain you wish to allow
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');

// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');

// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'YOUR-CUSTOM-HEADERS-HERE');

// Set to true if you need the website to include cookies in  requests
res.setHeader('Access-Control-Allow-Credentials', true);

// Check if Preflight Request
if (req.method === 'OPTIONS') {
    res.status(200);
        res.end();
}
else {
    // Pass to next layer of middleware
    next();
}

In this way, the client will be authorized and you will be able to set your custom headers in all the requests. In your case, you'll have to set x-id in the Access-Control-Allow-Headers option.

Matteo Tosi
  • 434
  • 4
  • 8
1

In your case the server has to respond to the preflight request with following headers:

Access-Control-Allow-Origin: *

X-Custom-HeaderAccess-Control-Allow-Methods: GET, POST, PUT, DELETE

Access-Control-Allow-Headers: x-id

Note that for the Access-Control-Allow-Origin HTTP header it's best practice to set the domain where the angular2 app is hosted explicitly instead of the * which is only necessary for public API's where you don't control all consumers!

I highly recommend you to read following article about CORS:

http://www.html5rocks.com/en/tutorials/cors/

Community
  • 1
  • 1
Daniel Gartmann
  • 11,678
  • 12
  • 45
  • 60
1

I have been developing an angular2 app with a c# web api back end and ran into an issue with the cors settings as well.

The real problem turned out not to be the cors settings, rather the data that was being sent to the api (js date object to c# datetime type didn't line up correctly). However in your case, is it absolutely essential to pass the x-id in the header rather than as a parameter on the request? For example you could do somthing like this:

getYourDataType(id: number): Observable<YourDataType> {
    return this.http.get(url + '/' + id.toString())
        .map((response: Response) => <YourDataType>response.json());

From my research after dealing with this issue it seems like angular would try to find the endpoint you were trying to hit, fail to find it and then assume that the reason must be something wrong with the cors settings, rather than the client side data.

You said that the api returns data when you don't set any headers on your request, so if changing from a header to a parameter doesn't work, you could try inspecting the request with a tool like fiddler or the network tab of chrome's dev tools and see if angular constructed each request as you expect it should have. Or comparing the results by manually constructing a request in fiddler, it could be very illuminating as to what exactly is happening to give you this unexpected response.

At any rate figuring out that there is an issue with your data, rather than the cors settings is quite difficult. Angular has you looking at the totally wrong thing trying to figure out a very simple problem. I hope this helps somebody.

Nikhil
  • 3,711
  • 8
  • 32
  • 43
0

the problem is that you also need to set the allowed headers. That's why it's not working. To make it work with a simple angular2 http request, you need to add the following headers:

    header('Access-Control-Allow-Origin: *');
    header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept"); // In your case also add x-id or what you are also using. 
    header('Access-Control-Allow-Methods: POST, PUT, DELETE, GET, OPTIONS');
G.T.
  • 562
  • 8
  • 18
0

Try following code, This should work

let headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/json');
headers.append('x-id','1');
this.http.get(url, {'headers': headers}).subscribe(
  response => {...},
  error => {...}
);
Akhilesh Kumar
  • 9,085
  • 13
  • 57
  • 95