Shaddow
Shaddow

Reputation: 3215

Angular2 Headers

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.

Upvotes: 15

Views: 6462

Answers (6)

OrbitalSloth
OrbitalSloth

Reputation: 19

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.

Upvotes: 1

Daniel Gartmann
Daniel Gartmann

Reputation: 13008

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/

Upvotes: 1

Akhilesh Kumar
Akhilesh Kumar

Reputation: 9355

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 => {...}
);

Upvotes: 0

Matteo Tosi
Matteo Tosi

Reputation: 434

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.

Upvotes: 6

G.T.
G.T.

Reputation: 562

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');

Upvotes: 0

Thierry Templier
Thierry Templier

Reputation: 202196

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

Upvotes: 7

Related Questions