Reputation: 3215
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
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
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
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
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
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
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