OPTIONS request is not firing with http call through Angular2 Http - angularjs

I am playing a bit with Angular2 structure and I got to the point where I want to pull information from the server.
Now, my api's domain is different from the FrontEnd app, and I am expecting that the browser will fire OPTIONS request before executing the actual one. However, that is not happening. Instead, what I get is an error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:8080/rrm/api/v1/goals.
(Reason: CORS header 'Access-Control-Allow-Origin' missing).
And my network log looks like this:
My dead simple Angular2 code is as follows:
export class AppComponent implements OnInit {
goals: Object[];
constructor(public authHttp: AuthHttp) {}
ngOnInit():any {
this.getGoals();
}
getGoals() {
this.authHttp.get('http://localhost:8080/rrm/api/v1/goals')
.subscribe(
data => this.goals = data.arrayBuffer(),
err => console.log('Error ', err),
() => console.log('Request Complete')
);
}
}
What am i missing? I am not getting options request on the server and I don't see it in the browser...
Thanks,

In fact, there are two main cases in CORS:
Simple requests. We are in this case if we use HTTP methods GET, HEAD and POST. In the case of POST method, only content types with following values are supported: text/plain, application/x-www-form-urlencoded, multipart/form-data. Even if you're in these case and if you use a custom header (a header that you define by your own in your request), you'll fall into the preflighted request.
Preflighted requests. When you aren't in the case of simple requests, a first request (with HTTP method OPTIONS) is done to check what can be done in the context of cross-domain requests.
In your case, you're in the first case (simple request).
Moreover your GET request should define a Access-Control-Allow-Origin header in its response not to have the error. This will allow the browser to determine if you're (localhost:3000 for example) able to execute the request.
This article could interest you:
http://restlet.com/blog/2015/12/15/understanding-and-using-cors/

The OPTIONS is only sent befor every POST request. For GET requests an OPTIONS preflight request is only sent if you have custom headers like auth-headers.
See also Why am I getting an OPTIONS request instead of a GET request?

Related

How to properly setup the barryvdh/laravel-cors in reactjs

I am currently new in ReactJS and facing problem regarding getting the response of API the console log shows of error of this
Access to XMLHttpRequest at 'https://facebook.github.io/react-native/movies.json' from origin 'http://localhost:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
they recommend to me that I use the barryvdh/laravel-cors to allow the cors in my API. I will show you guys my front-end code.
componentDidMount() {
axios.get('https://facebook.github.io/react-native/movies.json',{
}).then(function(response){
console.log(response)
})
}
In my logs, I will share here the captured image.
The error is in your Axios request itself, if you clearly see
axios.get('https://facebook.github.io/react-native/movies.json',{})
You've an additional parameter, While you are not passing any headers or other parameters, if you remove the {} then it should work.
axios.get('https://facebook.github.io/react-native/movies.json')
And if you see the results of your console you can see on where it clearly states that OPTIONS request is throwing a 405 status code,
from MDN
The HyperText Transfer Protocol (HTTP) 405 Method Not Allowed response
status code indicates that the request method is known by the server
but is not supported by the target resource.
You'll need to directly access the resource, probably your axios is generating Pre Flight Request with OPTIONS header due to {}, which is being rejected by the resource itself.
You can also try doing it with a simple fetch request,
fetch('https://facebook.github.io/react-native/movies.json')
.then(function(response) {
console.log(response.json())
})
CORS is controlled by backend API and in your case, you don't have control over it which is
https://facebook.github.io/react-native/movies.json.
Browser prevents your code from accessing the response because of the browser can't see Access-Control-Allow-Origin in response.
Things can still get working by making the request through a Proxy can where a proxy sends appropriate CORS header on behalf of your request.
const proxy = "https://cors-anywhere.herokuapp.com/";
const url = "https://facebook.github.io/react-native/movies.json";
fetch(proxy + url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("CORS Error" + url ))
Making a request through a proxy will work this way
CORS proxy will forward your request to https://facebook.github.io/react-native/movies.json
Return response from https://facebook.github.io/react-native/movies.json with Access-Control-Allow-Origin headers.
Now your browser can see Access-Control-Allow-Origin headers present in the response header.
For more detail explanation you can check out this
https://stackoverflow.com/a/43881141/2850383

API Request with HTTP Authorization Header inside of componentDidMount

I'm very new to React, and to practice, I am trying to build an application that fetches information from the Yelp API, but I'm having trouble getting a response. Yelp Fusion v3 requires an 'access_token'(which I've successfully received as a response in Postman). So to make this request in my application, I am using Axios. When I am making this request inside of componentDidMount(), as a response I get
XMLHttpRequest cannot load https://api.yelp.com/v3/businesses/search?term=sushi&location=Boston. 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:8080' is therefore not allowed access. The response had HTTP status code 500.
Though it may seem that I am incorrectly specifying the access_token and parameters, when running the same code in a separate file(not part of the application), I get the JSON response that I am looking for in my app.
Here is my componentDidMount():
componentDidMount: function () {
axios.get('https://api.yelp.com/v3/businesses/search?term=Sushi&location=Boston',{
headers: {
Authorization: `Bearer ${token}`
}
})
.then(function(res){
console.log(res)
})
.catch(function(err){
console.log(err)
})
},
I've tried the Yelp node module as well, but I am having no luck. Please help!
This error is a Cross-Origin error.
Web browsers have a catch with AJAX requests: They need to be addressed to the same origin or be authorized by the third-party itself, otherwise they are blocked. Since you have no control over Yelp, I suggest you take a workaround.
Available workarounds
You use something like jsonp. This method basically consists in making the request in a <script> tag. The server will wrap the response inside a Javascript script and it will be loaded unto the page. (https://en.wikipedia.org/wiki/JSONP). The server MUST offer this format for that workaround to work.
You use a reverse proxy. You can set NodeJS to act as one. In this setup, you will make your yelp request to your origin who will redirect it to the yelp server. This works because your Node proxy does not have the same limitations as your browser. (ex: https://github.com/nodejitsu/node-http-proxy)
There may be other ways to get around this, but those are popular methods.
Hope this helps.

How to call api from another domain angular typescript?

I want to call web service from another domain using angular2 typescript.
i am using following code to call api
var req_dict = {
method: RequestMethod.Get,
url: 'http//127.0.0.1:5000/users/',
headers: this.head
}
var options = new RequestOptions(req_dict);
var req = new Request(options);
this.http.request(req).subscribe({});
I hosted my application in http//127.0.0.1:8000. I want to use api from port 5000. when i inspected console , request is going to
http://127.0.0.1:8000/http//127.0.0.1:5000/users/
i want to call just http//127.0.0.1:5000/users/. how can call api by absolute url in angular2 ?
In fact, it's not an issue of TypeScript or Angular2 but a CORS issue. These blog posts could help you to understand in details how this works:
http://restlet.com/blog/2015/12/15/understanding-and-using-cors/
http://restlet.com/blog/2016/09/27/how-to-fix-cors-problems/
To be short, in the case of cross domain request, the browser automatically adds an Origin header in the request. There are two cases:
Simple requests. This use case applies if we use HTTP GET, HEAD and POST methods. In the case of POST methods, only content types with the following values are supported: text/plain, application/x-www-form-urlencoded and multipart/form-data.
Preflighted requests. When the "simple requests" use case doesn't apply, a first request (with the HTTP OPTIONS method) is made to check what can be done in the context of cross-domain requests.
So in fact most of work must be done on the server side to return the CORS headers. The main one is the Access-Control-Allow-Origin one.
200 OK HTTP/1.1
(...)
Access-Control-Allow-Origin: *
To debug such issues, you can use developer tools within browsers (Network tab).
Regarding Angular2, simply use the Http object like any other requests (same domain for example):
return this.http.get('https://angular2.apispark.net/v1/companies/')
.map(res => res.json()).subscribe(
...
);
Hope it helps you,
Thierry

Access-Control-Allow-Origin error but request goes through

I'm currently deploying a basic API to my live server and I'm running into (what I think is) a CORS problem but there is some behavior going on that I can't explain.
I'm communicating from an AngularJS front-end to a Laravel 5 (+ laravel-cors) back-end.
I started testing with a simple jQuery AJAX call (below) and when I make a request from my local Vagrant environment (http://dev.example.local/test.html) to http://api.example.com/v1/matches I get an error about Access-Control-Allow-Origin. The weird thing is that the request does come through because the information is stored in the database via the Laravel-based API correctly.
$.ajax({
method: 'POST',
url: 'http://api.example.com/v1/players',
data: {
"username": "username",
"first_name": "First",
"last_name": "Last",
"nickname": ""
}
}).always(function(r) {
console.log(r);
});
Error:
XMLHttpRequest cannot load http://api.example.com/v1/players. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://other.example.com' is therefore not allowed access.
The console.log(r) returns {readyState: 0, responseJSON: undefined, status: 0, statusText: "error"}
I developed the application locally using a Homestead VM (API) and a Vagrant environment (application) and it's working correctly within these environments...
Some observations:
Each of these requests shows up with Method: POST, Status: 200 OK, Type: xhr in my Chrome Developer Tools.
Tools like Postman and PhpStorm's RESTful service tester correctly execute the request and the data is added without errors.
Any ideas on how to further debug this problem are welcome... I've been trying to wrap my head around this for the entire day now and I just don't know what's causing it.
Your server must return an appropriate Access-Control-Allow-Origin header in the response. For example, if the request is being sent from http://stackoverflow.com, then your server must return this header: Access-Control-Allow-Origin: http://stackoverflow.com. You can determine, server-side, what the origin is by looking at the Origin header on the request. If your server does not return this header in the response, you will not have any access to the properties of the response browser-side (such as the status code, headers, or message body). The Same Origin Policy is at the center of this restriction.
The reason you are not seeing any similar issues when the request is sent by Postman or PhpStorm's RESTful service tester is due to the fact that these services do not send an Origin header with the request, as they are not subject to the Same Origin policy. By default, the browser will append this header to any cross-origin ajax requests, as browsers are subject to the Same Origin Policy. In my previous scenario, the request header would look like this: Origin: http://stackoverflow.com. Browsers that implement the CORS spec are required to add this request header so the server is able to determine if the origin of the request has been whitelisted for cross-origin ajax requests. If this is the case, the server will return the proper Access-Control-Allow-Origin header. If not, it can simply omit the header. Browsers that do not implement the CORS spec will simply refuse to send such an ajax request.
Regarding your bewilderment as to why the request is being sent in the first place, that comes down to a distinction between "simple" and "non-simple" CORS requests. For simple CORS requests, the request will always be sent to the server, but the client/JS will not be able to parse the response without proper acknowledgement from the server. Some CORS requests are not simple, so to speak. These are, for example, DELETE or PATCH requests, or POST/GET requests that contain non-standard headers (such as X-headers or a Content-Type of "application/json" as opposed to "multipart/form-data"). In other words, a request is not simple if it cannot be sent without JavaScript. For example, a <form> submit, or a GET request from a <script src="..."> will always send "simple" requests. For non-simple requests, the browser must "preflight" the request. This means that the browser sends an intermediate request, called a preflight, before the original request. This preflight request is an OPTIONS request. The server must than return headers in the response to this preflight that acknowledge any non-standard properties of the original request. If it does, then the browser will send the original request.
You can read more about preflighting and CORS in general on MDN.

Restangular prevent 'preflight' OPTIONS call

I'm trying to figure out how to prevent the OPTIONS call from firing on every GET call to our API server.
I'm trying this right now:
.config(function(RestangularProvider) {
RestangularProvider.setDefaultHeaders({"X-Requested-With" :"", "Content-Type": "text/plain"});
})
But it's not doing me any good. Everything still thinks it's application/json so it fires off the preflight call. Is there anything I can do?
Check this out:
OPTIONS requests are what we call pre-flight requests in Cross-origin
resource sharing (CORS).
They are necessary when you're making requests across different
origins.
This pre-flight request is made by some browsers as a safety measure
to ensure that the request being done is trusted by the server.
Meaning the server understands that the method, origin and headers
being sent on the request are safe to act upon.
Your server should not ignore but handle these requests whenever
you're attempting to do cross origin requests.
How to disable OPTIONS request?

Resources