I'm trying to send some HTTP requests from my angular.js application to my server, but I need to solve some CORS errors.
The HTTP request is made using the following code:
functions.test = function(foo, bar) {
return $http({
method: 'POST',
url: api_endpoint + 'test',
headers: {
'foo': 'value',
'content-type': 'application/json'
},
data: {
bar:'value'
}
});
};
The first try ended up with some CORS errors. So I've added the following lines to my PHP script:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT');
header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding, X-Auth-Token, content-type');
The first error is now eliminated.
Now the Chrome's developer console shows me the following errors:
angular.js:12011 OPTIONS http://localhost:8000/test (anonymous
function)
423ef03a:1 XMLHttpRequest cannot load
http://localhost:8000/test. Response for preflight has invalid HTTP
status code 400
and the network request looks like I expected (HTTP status 400 is also expected):
I can't imagine how to solve the thing (and how to understand) why the request will send on localhost as OPTIONS and to remote servers as POST. Is there a solution how to fix this strange issue?
TL;DR answer
Explanation
The OPTIONS request is so called pre-flight request, which is part of Cross-origin resource sharing (CORS). Browsers use it to check if a request is allowed from a particular domain as follows:
The browser wants to send a request to a particular URL, let's say a POST request with the application/json content type
First, it sends the pre-flight OPTIONS request to the same URL
What follows depends on the pre-flight request's response HTTP status code:
If the server replies with a non-2XX status response, the browser won't send the actual request (because he knows now that it would be refused anyway)
If the server replies with a HTTP 200 OK (or any other 2XX) response, the browser will send the actual request, POST in your case
Solution
So, in your case, the proper header is present, you just have to make sure the pre-flight request's response HTTP status code is 200 OK or some other successful one (2XX).
Detailed Explanation
Simple requests
Browsers are not sending the pre-flight requests in some cases, those are so-called simple requests and are used in the following conditions:
One of the allowed methods:
- GET
- HEAD
- POST
Apart from the headers automatically set by the user agent (for example, Connection, User-Agent, etc.), the only headers which are allowed to be manually set are the following:
Accept
Accept-Language
Content-Language
Content-Type (but note the additional requirements below)
DPR
Downlink
Save-Data
Viewport-Width
Width
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
No event listeners are registered on any XMLHttpRequestUpload object used in the request; these are accessed using the XMLHttpRequest.upload property.
No ReadableStream object is used in the request.
Such requests are sent directly and the server simply successfully processes the request or replies with an error in case it didn't match the CORS rules. In any case, the response will contain the CORS headers Access-Control-Allow-*.
Pre-flighted requests
Browsers are sending the pre-flight requests if the actual request doesn't meet the simple request conditions, the most usually:
custom content types like application/xml or application/json, etc., are used
the request method is other than GET, HEAD or POST
the POST method is of an another content type than application/x-www-form-urlencoded, multipart/form-data or text/plain
You need to make sure that the response to the pre-flight request has the following attributes:
successful HTTP status code, i.e. 200 OK
header Access-Control-Allow-Origin: * (a wildcard * allows a request from any domain, you can use any specific domain to restrict the access here of course)
From the other side, the server may refuse the CORS request simply by sending a response to the pre-flight request with the following attributes:
non-success HTTP code (i.e. other than 2XX)
success HTTP code (e.g. 200 OK), but without any CORS header (i.e. Access-Control-Allow-*)
See the documentation on Mozilla Developer Network or for example HTML5Rocks' CORS tutorial for details.
I ran into a very similar problem writing an Angular 2 app - that uses a NODE server for the API.
Since I am developing on my local machine, I kept getting Cross Origin Header problems, when I would try to POST to the API from my Angular app.
Setting the Headers (in the node server) as below worked for GET requests, but my PUT requests kept posting empty objects to the database.
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT');
header('Access-Control-Allow-Headers: X-Requested-With, Content-Type,
Origin, Authorization, Accept, Client-Security-Token, Accept-
Encoding, X-Auth-Token, content-type');
After reading Dawid Ferenczy's post, I realized that the PREFLIGHT request was sending blank data to my server, and that's why my DB entries were empty, so I added this line in the NODE JS server:
if (req.method == "OPTIONS")
{
res.writeHead(200, {"Content-Type": "application/json"});
res.end();
}
So now my server ignores the PREFLIGHT request, (and returns status 200, to let the browser know everything is groovy...) and that way, the real request can go through and I get real data posted to my DB!
Just put
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header("HTTP/1.1 200 ");
exit;}
at the beginning of your serverside app and you should be fine.
For spring boot application, to enable cors request, use #CrossOrigin(origins = "*", maxAge = 3600) on your respective controller.
Refer this doc
The best is to :
have proxy.conf.json set:
{
"/api": {
"target": "http://localhost:8080",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
}
}
And then to make sure that URL that you are using in angular to send a request is relative (/api/something) and not absolute (localhost:8080/api/something). Because in that case the proxy won't work.
From Chrome v79+, OPTIONS Check(pre-flight request) will no longer appear in the network tab-Source
Related
We've created one EXE file using the CPP language and create one API like http://localhost:5800/get-id/. when I open in browser return me the perfect output.
When I used fetch in HTML > script page, then getting No "Access-Control-Allow-Origin" header is present on the requested resource.
Code1:
fetch("http://localhost:5800/get-id/", {method: 'GET').then(function(response) {
console.log(response.text());
}).catch(function(error) {
console.log('Request failed', error)
});
After research, I've added the mode: no-cors error lost but getting an empty response.
Code2:
fetch("http://localhost:5800/get-id/", {method: 'GET', mode: 'no-cors'}).then(function(response) {
console.log(response.text());
}).catch(function(error) {
console.log('Request failed', error)
});
If I use code2 in any inspect console then getting an empty body but when I open http://localhost:5800/get-id/ in the browser and try to hit code2 in the console then getting the perfect parameter.
It means, localhost domain it's working fine but when it's fetched from any domain through my error.
What is the proper solution for it? In C/CPP language how can we allow cors?
Strange:
when I hit from console, it's show me empty
For same request I checked network tab, show 200 OK with proper response / preview data
CORS is a complex topic, I usually use CORS middleware to handle it in Node.JS in Express server (maybe the code will be useful to solve this).
It's goal is to allow API on domain api-domain to list web applications that can use it, for example your application is on webapp-domain domain.
When application calls fetch('http://api-domain/get-id/') to another domain it is referred to as cross-origin call.
All browser do CORS preflight call like this to check for allowance:
OPTIONS /get-id/
Access-Control-Request-Method: GET
Access-Control-Request-Headers: origin, x-requested-with
Origin: http://webapp-domain
(please note it's an OPTION request to the API, not GET)
And response should list webapp-domain as allowed (and specify which HTTP methods are allowed)
HTTP/1.1 204 No Content
Connection: keep-alive
Access-Control-Allow-Origin: http://webapp-domain
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400
After the successful preflight call like this the browser will continue with fetch, for example, it will send GET request to http://api-domain/get-id/
P.S.
One of the ways to skip CORS is to set HTTP proxy in webapp-domain which will call api-domain on server-side and is not limited by CORS. See this answer for details.
logout(){
var destroySession='{"token":"'+this.token+'"}'
console.log("Session Destroy"+destroySession)
axios.post(eventBus.apiURL+'logout',{
headers: {
'Content-type': 'application/json',
},
body: destroySession,
}).then(response=>{
console.log("RESadas :: "+JSON.stringify(response.data))
alert("Logout successfully..!")
this.$router.push('/')
},error=>{
console.log(error);
alert("Some Issue for LogOut at Server Side..!")
});
window.localStorage.removeItem('token')
window.localStorage.removeItem('name')
this.$router.push('/')
}
<button #click="logout">Logout</button>
I have written a code for logout in vuejs, but at the time of click it sends two POST request and during session destroy problem occurs at server side.
As per Mozilla Developer Network,
Preflight Requests
Unlike “simple requests” (discussed above), "preflighted" requests
first send an HTTP request by the OPTIONS method to the resource on
the other domain, in order to determine whether the actual request is
safe to send. Cross-site requests are preflighted like this since they
may have implications to user data.
In particular, a request is preflighted if any of the following
conditions is true:
If the request uses any of the following methods:
Put
DELETE
CONNECT
OPTIONS
TRACE
PATCH
Or if, apart from the headers set automatically by
the user agent (for example, Connection, User-Agent, or any of the
other header with a name defined in the Fetch spec as a “forbidden
header name”), the request includes any headers other than those which
the Fetch spec defines as being a “CORS-safelisted request-header”,
which are the following:
Accept
Accept-Language
Content-Language
Content-Type (but note the additional requirements below)
DPR
Downlink
Save-Data
Viewport-Width
Width
Or if the Content-Type header has a
value other than the following:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Updated
Please read this answer on how to disable preflight requests: Link
I want to post input values in my webservice. I had many errors when I checked, I found that OPTIONS was used not POST
Here's my code:
var req = {
headers: {
'Content-Type':'application/json'
}
}
$http.post(url,req)
.then(
function(response){
},
function(response){
});
It's strange why I had OPTIONS not POST and how can I solve such problem? (I am using AngularJS)
From the access-control-request-method header, you're looking at a CORS preflight request. These happen when you're going across origins, before the actual request is sent. The server may respond with headers to indicate whether the actual request is allowed or not, based on source origin, method, etc.
From the MDN docs, any POST request sending JSON will have a corresponding preflight request:
In particular, a request is preflighted if:
It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or text/plain,
e.g. if the POST request sends an XML payload to the server using
application/xml or text/xml, then the request is preflighted.
I'm trying to set a POST via an AJAX call to register some basic data from a webpage. This is supposed to be a public web service so the request can be sent from any domain, by including a JS script.
However when executing the request i got an error :
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'xxxxxx' is therefore not allowed access.
The response had HTTP status code 422.
The server response is set with the following :
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'POST, PUT, DELETE, GET, OPTIONS'
response.headers['Access-Control-Request-Method'] = '*'
response.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
And here is the JS request :
var params = "f="+_.open+"&t="+_.t0;
xmlhttp.open("POST",TRACKURL,true);
xmlhttp.send(params);
I guess something is missing in the request but i can't find how to fix it.
If you have idea, i'd be happy to hear it.
thnaks
I finally found an answer to my problem, if this can help anyone else : Actually the browser send a OPTIONS request before the POST request so in order to create a cross domain AJAX request you need to set headers in both the POST response and the OPTIONS response. This can be done in your application or in the web server configuration.
You need to use an XMLHttpRequest2 or an XDomainRequest (IE) object on the client.
I am trying to make a cross domain HTTP request to WCF service (that I own). I have read several techniques for working with the cross domain scripting limitations. Because my service must accommodate both GET and POST requests I cannot implement some dynamic script tag whose src is the URL of a GET request. Since I am free to make changes at the server I have begun to try to implement a workaround that involves configuring the server responses to include the "Access-Control-Allow-Origin" header and 'preflight' requests with and OPTIONS request. I got the idea from this post : Getting CORS working
At the server side, my web method is adding 'Access-Control-Allow-Origin: *' to the HTTP response. I can see that responses do include this header now. My question is: How do I 'preflight' a request (OPTIONS)? I am using jQuery.getJSON to make the GET request but the browser cancels the request right away with the infamous:
Origin http://localhost is not allowed by Access-Control-Allow-Origin
Is anyone familiar with this CORS technique? What changes need to be made at the client to preflight my request?
Thanks!
During the preflight request, you should see the following two headers: Access-Control-Request-Method and Access-Control-Request-Headers. These request headers are asking the server for permissions to make the actual request. Your preflight response needs to acknowledge these headers in order for the actual request to work.
For example, suppose the browser makes a request with the following headers:
Origin: http://yourdomain.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header
Your server should then respond with the following headers:
Access-Control-Allow-Origin: http://yourdomain.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: X-Custom-Header
Pay special attention to the Access-Control-Allow-Headers response header. The value of this header should be the same headers in the Access-Control-Request-Headers request header, and it can not be '*'.
Once you send this response to the preflight request, the browser will make the actual request. You can learn more about CORS here: http://www.html5rocks.com/en/tutorials/cors/
Although this thread dates back to 2014, the issue can still be current to many of us. Here is how I dealt with it in a jQuery 1.12 /PHP 5.6 context:
jQuery sent its XHR request using only limited headers; only 'Origin' was sent.
No preflight request was needed.
The server only had to detect such a request, and add the "Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN'] header, after detecting that this was a cross-origin XHR.
PHP Code sample:
if (!empty($_SERVER['HTTP_ORIGIN'])) {
// Uh oh, this XHR comes from outer space...
// Use this opportunity to filter out referers that shouldn't be allowed to see this request
if (!preg_match('#\.partner\.domain\.net$#'))
die("End of the road if you're not my business partner.");
// otherwise oblige
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
}
else {
// local request, no need to send a specific header for CORS
}
In particular, don't add an exit; as no preflight is needed.
Solve the CORS issue by writing your custom middleware in Node.js with these simple steps.
don't need to set anything from the client, just a little change on the Node.js server will fix the problem.
create a middleware:
// in middleware/corsResolver.js
function corsResolver(req, res, next) {
// Website you wish to allow to connect
// running front-end application on port 3000
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,Authorization');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
}
module.exports = corsResolver;
now edit your server.js (index.js or any main file that starts your node server) and add this middleware:
// server.js or indes.js
const corsResolver = require('path/to/resolver-middleware')
app.use(corsResolver) // -----------> applied middleware here
// other stuff