I have followed this step to setup my server to enable CORS.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
But now in my browser dev console, I see this error message:
XMLHttpRequest cannot load https://serveraddress/abc. Response for
preflight is invalid (redirect)
Do you know what can I do to fix it? I am making a CORS request in HTTPS. I think that is causing the 'preflight is invalid (redirect)' failure. But I don't know why or what is redirecting the OPTIONS request.
Thank you.
Short answer: Ensure the request URL in your code isn’t missing a trailing slash.
A missing-trailing-slash problem is the most-common cause of the error cited in the question.
But that’s not the only cause — just the most common. Read on for more details.
When you see this error, it means your code is triggering your browser to send a CORS preflight OPTIONS request, and the server’s responding with a 3xx redirect. To avoid the error, your request needs to get a 2xx success response instead.
You may be able to adjust your code to avoid triggering browsers to send the OPTIONS request.
As far as what all’s going on in this case, it’s important to know browsers do a CORS preflight if:
the request method is anything other than GET, HEAD, or POST
you’ve set custom request headers other than Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, or Width
the Content-Type request header has a value other than application/x-www-form-urlencoded, multipart/form-data, or text/plain
If you can’t change your code to avoid need for browsers to do a preflight, another option is:
Check the URL in the Location response header in the response to the OPTIONS request.
Change your code to make the request to that other URL directly instead.
The difference between the URLs might be something as simple as a trailing slash in the path — for example, you may need to change the URL in your code to add a trailing slash — e.g., http://localhost/api/auth/login/ (notice the trailing slash) rather than http://localhost/api/auth/login (no trailing slash) — or you might instead need to remove a trailing slash.
You can use the Network pane in browser devtools to examine the response to the OPTIONS request and to find the redirect URL in the value of the Location response header.
However, in some cases, all of the following will be true:
you’re not able to avoid the preflight OPTIONS
you’re not able to make any adjustments to the request URL
you’re not able to replace the request URL with a completely different URL
A common case with those conditions is when you try to work with some 3rd-party endpoint that requires an OAuth or SSO workflow that’s not intended to be used from frontend code.
In such cases — in all cases, actually — what’s essential to realize is that the response to the preflight must come from the same origin to which your frontend code sent the request.
So even if you create a server-side proxy that you control:
If your browser sends a preflight OPTIONS request to your proxy.
You’ve configured the proxy such that it just redirects the request to a 3rd-party endpoint.
Thus, your frontend ends up receiving a response directly from that 3rd-party endpoint.
…then the preflight will fail.
In such a case ultimately your only alternative is: ensure the preflight isn’t just redirected to the 3rd-party endpoint but instead your own server-side (proxy) code receives the response from that endpoint, consumes it, and then sends a response of its own back to your frontend code.
This happens sometimes when you try calling an https service as http, for example when you perform a request on:
'http://example.com/api/v2/tickets'
Which should be:
'https://example.com/api/v2/tickets'
First of all, ensure that you have "Access-Control-Allow-Origin": "*" in the headers
then just remove "/" at the end of url
e.g. change
url: "https://facebook/api/login/"
into
url: "https://facebook/api/login" (without '/')
In my case I did not have to set the request header to have "Access-Control-Allow-Origin": "*". The url HAD TO be ending with a "/" at the end
in my case i also solve this preflight request by just putting one slash (/) at the end of the api
#django #reactJs
The CORS request was responded to by the server with an HTTP redirect to a URL on a different origin than the original request, which is not permitted during CORS requests.
For example, if the page https://service.tld/fetchdata were requested, and the HTTP response is "301 Moved Permanently", "307 Temporary Redirect", or "308 Permanent Redirect" with a Location of https://anotherservice.net/getdata, the CORS request will fail in this manner.
To fix the problem, update your code to use the new URL as reported by the redirect, thereby avoiding the redirect.The CORS request was responded to by the server with an HTTP redirect to a URL on a different origin than the original request, which is not permitted during CORS requests.
For example, if the page https://service.tld/fetchdata were requested, and the HTTP response is "301 Moved Permanently", "307 Temporary Redirect", or "308 Permanent Redirect" with a Location of https://anotherservice.net/getdata, the CORS request will fail in this manner.
To fix the problem, update your code to use the new URL as reported by the redirect, thereby avoiding the redirect.
I am building a web API. I found whenever I use Chrome to POST, GET to my API, there is always an OPTIONS request sent before the real request, which is quite annoying. Currently, I get the server to ignore any OPTIONS requests. Now my question is what's good to send an OPTIONS request to double the server's load? Is there any way to completely stop the browser from sending OPTIONS requests?
edit 2018-09-13: added some precisions about this pre-flight request and how to avoid it at the end of this reponse.
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 in specific situations.
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.
A good resource can be found here http://enable-cors.org/
A way to handle these to get comfortable is to ensure that for any path with OPTIONS method the server sends a response with this header
Access-Control-Allow-Origin: *
This will tell the browser that the server is willing to answer requests from any origin.
For more information on how to add CORS support to your server see the following flowchart
http://www.html5rocks.com/static/images/cors_server_flowchart.png
edit 2018-09-13
CORS OPTIONS request is triggered only in somes cases, as explained in MDN docs:
Some requests don’t trigger a CORS preflight. Those are called “simple requests” in this article, though the Fetch spec (which defines CORS) doesn’t use that term. A request that doesn’t trigger a CORS preflight—a so-called “simple request”—is one that meets all the following conditions:
The only allowed methods are:
GET
HEAD
POST
Apart from the headers set automatically by the user agent (for example, Connection, User-Agent, or any of the other headers with names defined in the Fetch spec as a “forbidden header name”), the only headers which are allowed to be manually set are those which the Fetch spec defines as being a “CORS-safelisted request-header”, which are:
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.
Have gone through this issue, below is my conclusion to this issue and my solution.
According to the CORS strategy (highly recommend you read about it) You can't just force the browser to stop sending OPTIONS request if it thinks it needs to.
There are two ways you can work around it:
Make sure your request is a "simple request"
Set Access-Control-Max-Age for the OPTIONS request
Simple request
A simple cross-site request is one that meets all the following conditions:
The only allowed methods are:
GET
HEAD
POST
Apart from the headers set automatically by the user agent (e.g. Connection, User-Agent, etc.), the only headers which are allowed to be manually set are:
Accept
Accept-Language
Content-Language
Content-Type
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
A simple request will not cause a pre-flight OPTIONS request.
Set a cache for the OPTIONS check
You can set a Access-Control-Max-Age for the OPTIONS request, so that it will not check the permission again until it is expired.
Access-Control-Max-Age gives the value in seconds for how long the response to the preflight request can be cached for without sending another preflight request.
Limitation Noted
For Chrome, the maximum seconds for Access-Control-Max-Age is 600 which is 10 minutes, according to chrome source code
Access-Control-Max-Age only works for one resource every time, for example, GET requests with same URL path but different queries will be treated as different resources. So the request to the second resource will still trigger a preflight request.
Please refer this answer on the actual need for pre-flighted OPTIONS request: CORS - What is the motivation behind introducing preflight requests?
To disable the OPTIONS request, below conditions must be satisfied for ajax request:
Request does not set custom HTTP headers like 'application/xml' or 'application/json' etc
The request method has to be one of GET, HEAD or POST. If POST, content type should be one of application/x-www-form-urlencoded, multipart/form-data, or text/plain
Reference:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
When you have the debug console open and the Disable Cache option turned on, preflight requests will always be sent (i.e. before each and every request). if you don't disable the cache, a pre-flight request will be sent only once (per server)
Yes it's possible to avoid options request. Options request is a preflight request when you send (post) any data to another domain. It's a browser security issue. But we can use another technology: iframe transport layer. I strongly recommend you forget about any CORS configuration and use readymade solution and it will work anywhere.
Take a look here:
https://github.com/jpillora/xdomain
And working example:
http://jpillora.com/xdomain/
For a developer who understands the reason it exists but needs to access an API that doesn't handle OPTIONS calls without auth, I need a temporary answer so I can develop locally until the API owner adds proper SPA CORS support or I get a proxy API up and running.
I found you can disable CORS in Safari and Chrome on a Mac.
Disable same origin policy in Chrome
Chrome: Quit Chrome, open an terminal and paste this command: open /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir
Safari: Disabling same-origin policy in Safari
If you want to disable the same-origin policy on Safari (I have 9.1.1), then you only need to enable the developer menu, and select "Disable Cross-Origin Restrictions" from the develop menu.
As mentioned in previous posts already, OPTIONS requests are there for a reason. If you have an issue with large response times from your server (e.g. overseas connection) you can also have your browser cache the preflight requests.
Have your server reply with the Access-Control-Max-Age header and for requests that go to the same endpoint the preflight request will have been cached and not occur anymore.
I have solved this problem like.
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && ENV == 'devel') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With');
header("HTTP/1.1 200 OK");
die();
}
It is only for development. With this I am waiting 9ms and 500ms and not 8s and 500ms. I can do that because production JS app will be on the same machine as production so there will be no OPTIONS but development is my local.
You can't but you could avoid CORS using JSONP.
After spending a whole day and a half trying to work through a similar problem I found it had to do with IIS.
My Web API project was set up as follows:
// WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
//...
}
I did not have CORS specific config options in the web.config > system.webServer node like I have seen in so many posts
No CORS specific code in the global.asax or in the controller as a decorator
The problem was the app pool settings.
The managed pipeline mode was set to classic (changed it to integrated) and the Identity was set to Network Service (changed it to ApplicationPoolIdentity)
Changing those settings (and refreshing the app pool) fixed it for me.
OPTIONS request is a feature of web browsers, so it's not easy to disable it. But I found a way to redirect it away with proxy. It's useful in case that the service endpoint just cannot handle CORS/OPTIONS yet, maybe still under development, or mal-configured.
Steps:
Setup a reverse proxy for such requests with tools of choice (nginx, YARP, ...)
Create an endpoint just to handle the OPTIONS request. It might be easier to create a normal empty endpoint, and make sure it handles CORS well.
Configure two sets of rules for the proxy. One is to route all OPTIONS requests to the dummy endpoint above. Another to route all other requests to actual endpoint in question.
Update the web site to use proxy instead.
Basically this approach is to cheat browser that OPTIONS request works. Considering CORS is not to enhance security, but to relax the same-origin policy, I hope this trick could work for a while. :)
you can also use a API Manager (like Open Sources Gravitee.io) to prevent CORS issues between frontend app and backend services by manipulating headers in preflight.
Header used in response to a preflight request to indicate which HTTP headers can be used when making the actual request :
content-type
access-control-allow-header
authorization
x-requested-with
and specify the "allow-origin" = localhost:4200 for example
One solution I have used in the past - lets say your site is on mydomain.com, and you need to make an ajax request to foreigndomain.com
Configure an IIS rewrite from your domain to the foreign domain - e.g.
<rewrite>
<rules>
<rule name="ForeignRewrite" stopProcessing="true">
<match url="^api/v1/(.*)$" />
<action type="Rewrite" url="https://foreigndomain.com/{R:1}" />
</rule>
</rules>
</rewrite>
on your mydomain.com site - you can then make a same origin request, and there's no need for any options request :)
It can be solved in case of use of a proxy that intercept the request and write the appropriate headers.
In the particular case of Varnish these would be the rules:
if (req.http.host == "CUSTOM_URL" ) {
set resp.http.Access-Control-Allow-Origin = "*";
if (req.method == "OPTIONS") {
set resp.http.Access-Control-Max-Age = "1728000";
set resp.http.Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, PATCH, OPTIONS";
set resp.http.Access-Control-Allow-Headers = "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since";
set resp.http.Content-Length = "0";
set resp.http.Content-Type = "text/plain charset=UTF-8";
set resp.status = 204;
}
}
What worked for me was to import "github.com/gorilla/handlers" and then use it this way:
router := mux.NewRouter()
router.HandleFunc("/config", getConfig).Methods("GET")
router.HandleFunc("/config/emcServer", createEmcServers).Methods("POST")
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
log.Fatal(http.ListenAndServe(":" + webServicePort, handlers.CORS(originsOk, headersOk, methodsOk)(router)))
As soon as I executed an Ajax POST request and attaching JSON data to it, Chrome would always add the Content-Type header which was not in my previous AllowedHeaders config.
I was looking for the specific security reasons as to why this was added. It was kind of a WTH moment when I was implementing cors and could see all the headers being returned but I couldn't access them via javascript..
CORS is implemented in such a way that it does not break assumptions made in the pre-CORS, same-origin-only world.
In the pre-CORS world, a client could trigger a cross-origin request (for example, via a script tag), but it could not read the response headers.
In order to ensure that CORS doesn't break this assumption, the CORS spec requires the server to give explicit permissions for the client to read those headers (via the Access-Control-Expose-Headers header). This way, unauthorized CORS requests behave as they did in a pre-CORS world.
Here is the reason why Access-Control-Expose-Headers is needed :
Access-Control-Expose-Headers (optional) - The XMLHttpRequest 2 object has a getResponseHeader() method that returns the value of a particular response header. During a CORS request, the getResponseHeader() method can only access simple response headers. Simple response headers are defined as follows:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
If you want clients to be able to access other headers, you have to use the Access-Control-Expose-Headers header. The value of this header is a comma-delimited list of response headers you want to expose to the client.
for more reference please dig into the link https://www.html5rocks.com/en/tutorials/cors/
Happy coding !!
This is a pretty good question. Looking through http://www.w3.org/TR/cors/#simple-response-header, it's not obvious why you would want to or need to do this.
The CORS spec puts a lot of weight into the idea that you have to have a pre-request handshake where the client asks for a type of connection and the server responds that it'll allow it - so this may just be another aspect of that.
By default content-length isn't a permitted header so I ran into the same issue (later on when I needed to access WebDAV and had to modify the allowable params).. CORS really doesn't make a lot of sense (to me) in the first place so it wouldn't surprise me if swaths of it that are capricious.
I am using express-jwt to build a restful api. Now the client is making duplicate ajax calls, for the first one the initiator is angularjs and for the second one the initiator is other. The first one gets 204 as the response code and the second one gets 200 as the response code. I tried to debug to get to the source of this duplicate requests, but I am not able to.
Below is the header details for the one with 204 status code
Below is the header details for the one with 204 status code
Can any one suggest what could be the issue?
The first call is OPTIONS type. That's a pre-flight call which a browser sends if the page and api are not on same domain.
The purpose of this call is to deal with CORS. Backend usually needs to send the allowed request method types (GET, POST etc.). The browser will then send the real call if the desired request type is among those returned.
Here's a sample of the response headers.
You can ignore it for all intents and purposes. It does not contain any normally useful payload or return data.
Take a look at AJAX in Chrome sending OPTIONS instead of GET/POST/PUT/DELETE? for more info.
Those two requests are different one is OPTIONS and other is GET.
For cross-domain requests, setting the content type to anything other than application/x-www-form-urlencoded, multipart/form-data, or text/plain will trigger the browser to send a preflight OPTIONS request to the server.
You need to handle in the server when the request method OPTIONS , then you need to exit with out processing.
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?