I ham trying to make a request to a REST api. It is a CORS request.
My frontend : Angular 1.5 (localhost:3000)
My Backend : Django (*****.ddns.net)
So I am using a service ( made by someone who doesn't want to share the code :( ), that is doing a OPTIONS request before the real request (preflight). To be precise, the call is made through the resolve option of UI-router state definition.
Django has CORS to allow *.
This is the error that i get in google chrome :
XMLHttpRequest cannot load https://****.net/api/myprofile. The request was redirected to 'https://*****.net/punchclock/api/myprofile/', which is disallowed for cross-origin requests that require preflight.
If I do a classic $http request in a controller, it is working.
This is the request recieved my django :
+6655:5740d0f9:10|
OPTIONS /punchclock/api//myprofile HTTP/1.0|
Host:*****.net|
Connection:close|
Pragma:no-cache|
Cache-Control:no-cache|
Access-Control-Request-Method:GET|
Origin:http%3a//localhost%3a3000|
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36|
Access-Control-Request-Headers:accept, authorization|
Accept:*/*|
Referer:http%3a//localhost%3a3000/dashboard|
Accept-Encoding:gzip, deflate, sdch|
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,es;q=0.2
-6655:5740d0f9:10
And this is the response i get if I do it with postman (it is working with postman when i do an OPTIONS request)
Access-Control-Allow-Headers →x-requested-with, content-type, accept, origin, authorization, x-csrftoken
Access-Control-Allow-Methods →GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Origin →*
Access-Control-Max-Age →86400
Allow →GET, HEAD, OPTIONS
Connection →keep-alive
Content-Type →application/json
Date →Sat, 21 May 2016 21:15:02 GMT
Server →nginx/1.6.2
Transfer-Encoding →chunked
Vary →Accept
X-Frame-Options →SAMEORIGIN
I think it is an issue on Django's side, I don't know. If you have any idea... (I need to learn a lot about CORS...)
Make sure the URL you are targeting is correctly constructed and that there is a trailing slash at the end of the route you are calling. As mentioned here. So instead of this
'http://localhost:5000/auth'
you would call this
'http://localhost:5000/auth/'
Hope this helps.
It is probably because some of the headers you are sending are not allowed. To make sure, just go to google chrome debugger and copy the request headers and send them using postman. If it fails eliminate the headers until you find out which one is not allowed.
There is a similar answer here that may help. Specifically where it says
According to the W3 CORS Spec Section 6.2 Preflight Requests, the preflight must reject the request if any header submitted does not match the allowed headers.
Related
I need to make a CORS request from localhost. I have the Allow-Control-Allow-Origin Chrome plugin installed and turned on and when I hover over the menu item it shows: "Allow-Control-Allow-Origin: *". I created a .bat file with the following contents:
start chrome http://localhost:8080/MyPage.html --disable-web-security --user-data-di
This opens a new Chrome instance at the expected url but the CORS request still fails with the following error:
Failed to load [rest-url]: 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.
Can you recommend any workarounds for this?
could you show the code and give us some more information about the technology etc. which you are using?
It seems like you´re not sending a "preflight"-Request, your preflight-request does not contain the needed headers or your remote does not return the right headers:
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
Credits to: #monsur
See also: CORS - How do 'preflight' an httprequest?
the Access-Control-Request-Headers needs to contain all custom headers your sending allong with the real request, it will fail if not. At least for me, the error messages are somewhat cryptic and don´t always point in the right direction.
I am building a prototype application that does an Ajax GET call via javascript in an html page. The configuration I am using is:
Windows/Apache Web Server (XAMPP)
MongoDB
Chrome Browser
All running on the same Windows7(32) machine. The mongodb server and data are installed in the C:\ path; the Apache server is in the C:\XAMPP path. I can access the MongoDB server directly through the browser; for example a call to:
localhost:28017/ database/ collection
will return the collection's data in json format.
However, if I try running the same Ajax call in javascript via an html page, I get the error:
XMLHttpRequest cannot load http:// localhost:28017/ database/ collection. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http:// localhost' is therefore not allowed access.
I modified/inspected my httpd.conf file and have the following set for :
<Directory />
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "X-Requested-With, Content-Type,
Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
AllowOverride none
Require all denied
</Directory>
I also confirmed that the headers_module is being loaded:
LoadModule headers_module modules/mod_headers.so
However, this does not work. The port number is changing between the html and the ajax call (80 vs. 28017), therefore a new domain.
Here is the script code:
var xhr = new XMLHttpRequest();
console.log("xhr open")
xhr.open("GET", "http://localhost:28017/ database/ collection/", false);
xhr.send();
Here are the response headers from the html call:
Accept-Ranges:bytes
Access-Control-Allow-Headers:X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding
Access-Control-Allow-Methods:POST, GET, OPTIONS, DELETE, PUT
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1000
Connection:Keep-Alive
Content-Length:564
Content-Type:text/html
Date:Mon, 09 Jan 2017 23:47:06 GMT
ETag:"234-545b12ed82b40"
Keep-Alive:timeout=5, max=100
Last-Modified:Mon, 09 Jan 2017 22:49:41 GMT
Server:Apache/2.4.23 (Win32) OpenSSL/1.0.2h PHP/5.5.38
And all the headers from the xhr call:
General
Request URL:http://localhost:28017/ database/ collection/
Request Method:GET
Status Code:200 OK
Response Headers
Connection:close
Content-Length:369
Content-Type:text/plain;charset=utf-8
x-action:
x-ns:database.collection
Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Host:localhost:28017
Origin:http:// localhost
Referer:http://localhost/ load_mongodb_data.html
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Any assistance appreciated.
CORS is a mechanism where restricted Resources can be requested from (Shared to) another domain - i.e. "Cross Origin" ... the domain owning the resource controls who can have it - this is the important part of CORS, the owner of the resource permits or denies access to the resource
In your case, the page making the request is served on port 80, the resource is requested on port 28017
Think of port 80 as being your domain with your resources
Think of port 28017 being someone elses domain, and they have some resources you want to use
You can't "enable CORS" on your domain and expect the other domain to then grant you access to it's resources - if that's how CORS worked, there'd be no need for CORS to begin with
What you'll need to do is set those Access-Control-* headers on the server running on port 28017
I'm trying to send a file to rackspace via AJAX. This is my first time looking at CORS. I see in the documentation the option to send a preflight request, however since I personally set the header and know that my origin is valid I'm trying to forgo, these are the headers from my upload endpoint:
HTTP/1.1 204 No Content
Content-Length: 0
X-Container-Object-Count: 2
Accept-Ranges: bytes
X-Container-Meta-Access-Log-Delivery: false
X-Container-Meta-Access-Control-Expose-Headers: etag location x-timestamp x-trans-id
X-Timestamp: 1401852621.29287
X-Container-Meta-Access-Control-Allow-Origin: h ttp://localhost:8080**<-- (manually added the space after "h" so stackoverflow would let me submit)
X-Container-Bytes-Used: 5572910
Content-Type: text/plain; charset=utf-8
X-Trans-Id: txfc64055cb1114b6fb0ef6-0053a77a46ord1
Date: Mon, 23 Jun 2014 00:52:22 GMT
However, whenever I try to send the request it immediate fails in chrome with the following message:
XMLHttpRequest cannot load [**I'm redacting my actual endpoint**]. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'h ttp://localhost:8080' is therefore not allowed access.
Here are my request headers:
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryZSg4nEq8EDaXQQBu
Origin:h ttp://localhost:8080
Referer:h ttp://localhost:8080/tools/artwork
<-- (manually added the space after "h" so stackoverflow would let me submit)
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
What am I missing? Is preflight request required even if you know origin is permitted? I never see a packet come back to seems like Chrome isn't sending?
Yes, preflight is required any time your CORS request is not of the "simple" variety--meaning, you have a method other than GET, HEAD, or POST, a content type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, or your request sets a custom header.
Regardless of this, however, the response you've pasted does not contain Access-Control-Allow-Origin (it has X-Container-Meta-Access-Control-Allow-Origin) in the first place, which is why your request was rejected.
In your server,add Access-Control-Allow-Origin: http://foo.example header.
For example in Spring Controller, response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080");
Additional things,
Access-Control-Allow-Origin: http://foo.example // you can add as many urls separated by commas or '*' to allow all urs
Access-Control-Allow-Methods: POST, GET, OPTIONS // Request method options separated by commas
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000 // expiration in milliseconds
Refer this MDN site.
I am writing a web application for some service using RESTful API. The API is available at https://api.example and app at https://app.example. Simple GET requests using CORS are working just fine in Chrome and Firefox. Some method accept data via POST and return 303 code with new uri in Location header.
Preflight OPTIONS request is fine:
Request Method:OPTIONS
Status Code:200 OK
Request Headers
Accept:*/*
Accept-Charset:UTF-8,*;q=0.5
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Access-Control-Request-Headers:origin, authorization, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
DNT:1
Host:api.example
Origin:https://app.example
Referer:https://app.example/app/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.32 (KHTML, like Gecko) Chrome/27.0.1425.0 Safari/537.32 SUSE/27.0.1425.0
Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Authorization, Content-Type
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,HEAD,OPTIONS
Access-Control-Allow-Origin:https://app.example
Access-Control-Expose-Headers:*
Access-Control-Max-Age:3628800
Connection:keep-alive
Content-Length:0
Date:Sun, 05 May 2013 15:22:50 GMT
Server:nginx/1.2.5
Then the actual request just stop after receiving 303:
Request URL:https://api.example
Request Method:POST
Status Code:HTTP/1.1 303 See Other
Response headers:
Server:nginx/1.2.5
Location:https://api.example/some_url
Date:Sun, 05 May 2013 15:27:49 GMT
Content-Type:application/json
Content-Length:0
Connection:keep-alive
Access-Control-Max-Age:3628800
Access-Control-Expose-Headers:*
Access-Control-Allow-Origin:https://app.example
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,HEAD,OPTIONS
Access-Control-Allow-Headers:Authorization, Content-Type
Access-Control-Allow-Credentials:true
By RFC user agent should follow redirects, but Chrome and FF seems doesn't behave as expected. Is it a browsers' bug or I am doing something wrong?
update: If I start chromium with --disable-web-security everything works fine.
I've been wrestling with this, too. It appears that 3xx redirects for preflighted CORS requests are forbidden by the spec.
http://www.w3.org/TR/cors/
From the spec:
(Step 1. and 2. detail the preflighting process. And the we come to step...)
...3. This is the actual request. Apply the make a request steps and observe
the request rules below while making the request.
If the response has an HTTP status code of 301, 302, 303, 307, or 308
Apply the cache and network error steps.
And then if we scroll on down to http://www.w3.org/TR/cors/#cache-and-network-error-steps:
Whenever the network error steps are applied, terminate the algorithm
that invoked this set of steps and set the cross-origin request status
to network error.
Note: This has no effect on setting of user credentials. I.e. if the block
cookies flag is unset, cookies will be set by the response.
Whenever the cache and network error steps are applied, follow these
steps:
Remove the entries in the preflight result cache where origin field
value is a case-sensitive match for source origin and url field value
is a case-sensitive match for request URL.
Apply the network error steps acting as if the algorithm that invoked
the cache and network error steps invoked the network error steps
instead.
(Emphasis taken from the doc.)
3xx redirects are, however, permitted for simple CORS requests.
If its the chromium bug here is the possible errors on your code given by chromium suport:
If a same-origin request causes a redirect to a different origin,
do not enforce access control checks for the redirect response
itself, because the request which resulted in the redirect was
same-origin.
If a same-origin request causes a redirect to a different origin,
use the original request's URL as the origin for the new
request do not use a unique security origin.
Track whether the client (i.e., XMLHttpRequest) actually requested
that credentials be sent in the first place. When a
same-origin request redirects to a different origin, the original
request will send cookies whether requested or not, because it is
same-origin. The new cross-origin request should not send cookies
unless they were requested, so that the access control checks on
the response will succeed if the server granted
"Access-Control-Allow-Origin=*".
What I am trying to do is to have a page on the HTTP protocol sending an AJAX call to the same Web server but using HTTPS. Both the requesting page and the AJAX handler are on the same server, having the same domain and port. (I.e., only difference is the protocol.) To illustrate,
From
http://www.example.com/index.php
Triggers a jQuery AJAX call to
https://www.example.com/authenticate.php?user=123&password=456
(I am hoping to pass the password through HTTPS to make it encrypted over the Internet. Due to some design constraints I must use AJAX call instead of redirecting the page.)
I understand that there is a CORS issue here and thus I researched a bit and found that I could actually make use of the Access-Control-Allow-Origin header to help. I then set the following in my Apache's configuration file,
Header set Access-Control-Allow-Origin *
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header set Access-Control-Allow-Headers "content-type, accept"
Header set Access-Control-Max-Age 1000
I can see that when the browser requests the resources from the server, the headers can be seen. Request:
Accept */*
Accept-Encoding gzip, deflate
Accept-Language en-us,en;q=0.5
Authorization Basic Y2FzZXRhZ3JhbWRldjpwYXNzd29yZGRldiE=
Cache-Control no-cache
Connection keep-alive
Cookie __utma=99230732.2019724749.1337107099.1337849971.1337856946.9; __utmz=99230732.1337107099.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=217650581.954519005.1337107174.1337772401.1337777327.5; __utmz=217650581.1337107174.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=99230732; PHPSESSID=m8lnqhqv2qa6f884a8um413n81
Host www.example.com
Pragma no-cache
Referer http://www.example.com/index.php
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0
The response is like,
Accept-Ranges bytes
Access-Control-Allow-Head... content-type, accept
Access-Control-Allow-Meth... GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Orig... *
Access-Control-Max-Age 1000
Connection close
Content-Length 16599
Content-Type application/x-javascript
Date Thu, 24 May 2012 14:48:17 GMT
Etag "48157-40d7-4c0c938b220c0"
Last-Modified Thu, 24 May 2012 14:39:39 GMT
Server Apache/2.2.3 (CentOS)
So it looks like the header part is fulfilled. (Am I right?)
Then when I tried to call the follow jQuery AJAX code in JavaScript,
$.ajax({
// Use HTTPS as there is password transferred
url : "https://www.example.com/authentication.php",
type : 'POST',
dataType : 'json',
async : false,
data : ajaxData,
beforeSend : function(xhr, opt) {},
error : function(error) {
console.log("Ajax error: unable to login user: ");
console.log(error);
},
success : function(status) {
if(status==USER_AUTH_AUTHENTICATE_USER_SUCCESS) {
console.log("User login succeeded!");
} else {
console.log("User login failed.");
}
}
});
The browser (FireFox 12) will just return an object,
readyState 0
status 0
statusText "[Exception... "Access to restricted URI denied" code: "1012" nsresult: "0x805303f4 (NS_ERROR_DOM_BAD_URI)" location: "http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js Line: 8240"]"
Is there something that I missed out?
In fact I had already tried a lot of suggestions from forums and blogs trying to get this done but still I am unsuccessful. I also tried using JSONP and it works fine on FireFox but failed on Chrome/Safari with no readable error message but just throwing an error from jQuery code "head.insertBefore( script, head.firstChild );".
Appreciate much if someone can give me a clue on what is wrong with my code/settings.
Thanks!
Edited on 2012-05-25 20:29 (UTC +08:00)
As suggested I read this reference case (http://stackoverflow.com/questions/5750696/how-to-get-a-cross-origin-resource-sharing-cors-post-request-working) and I found that it linked to this case (http://stackoverflow.com/questions/5584923/a-cors-post-request-works-from-plain-javascript-but-why-not-with-jquery) as well which is related. I tried the sample XHR code there,
var request = new XMLHttpRequest();
var params = "action=something";
request.open('POST', 'https://www.example.com/controllers/Authentication.php', true);
request.onreadystatechange = function() {if (request.readyState==4) alert("It worked!");};
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", params.length);
request.setRequestHeader("Connection", "close");
request.send(params);
The code is called from a page with HTTP protocol. Once the code is executed, the error below is thrown right away,
Access to restricted URI denied...test_xhr.php Line 11
(If I change the HTTPS in JavaScript HTTP, the script works right away and so there should not be any syntax problem or so.)
The request and response headers of the page itself are as follows. Request is,
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-us,en;q=0.5
Authorization Basic Y2FzZXRhZ3JhbWRldjpwYXNzd29yZGRldiE=
Cache-Control no-cache
Connection keep-alive
Cookie __utma=99230732.2019724749.1337107099.1337856946.1337921578.10; __utmz=99230732.1337107099.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=217650581.954519005.1337107174.1337772401.1337777327.5; __utmz=217650581.1337107174.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=99230732; PHPSESSID=ktd6anojfi40ohemlujosdmhi4
Host www.example.com
Pragma no-cache
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0
The response is,
Access-Control-Allow-Head... content-type, accept
Access-Control-Allow-Meth... GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Orig... *
Access-Control-Max-Age 1000
Connection close
Content-Length 590
Content-Type text/html; charset=UTF-8
Date Fri, 25 May 2012 12:24:44 GMT
Server Apache/2.2.3 (CentOS)
X-Powered-By PHP/5.1.6
So I am just thinking something is fundamentally wrong with my setup but not jQuery as native XHR does not work as well. :(
You have two issues:
1) Access-Control-Allow-Origin "*" is not working with authenticated calls, instead of * reflect the calls Access-Control-Request-Origin or Origin header fields.
2) You'll need Access-Control-Allow-Credentials: true in the response.
Other things that might help: setting authorization header manually, assembling name and password with base64. This is the surest way to have working. Its advantage is its drawback: setting authorization header manually activates the OPTIONS header based CORS handshake. (All your requests are preceded with an OPTIONS request that you have to also handle) This one seems to have a coherent implementation across all modern browsers (IE9 of course is an exception, IE10 however works allegedly).
HTH