On Firefox 12, when I consecutively request two resources with the same URI but with different request headers (different accept fields), response is the cached response of the first request. First request is text/html request of the page which is correctly returned and the second request is like this:
Requested URL is: http://localhost:8080/test/ with these headers:
Response Headers
Content-Type text/html;charset=ISO-8859-1
Date Sun, 29 Apr 2012 19:41:53 GMT
Server Apache-Coyote/1.1
Request Headers
Accept application/json
Accept-Encoding gzip, deflate
Accept-Language en-us,en;q=0.5
Connection keep-alive
Cookie JSESSIONID=DB75F9F730D72D040CB5781903B60E87
Host localhost:8080
Referer http://localhost:8080/test/
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0
X-Requested-With XMLHttpRequest
Do you have any suggestions to avoid this problem? Thanks in advance.
If your server is sending different content based on different Accept headers, it should be sending "Vary: Accept" to tell caches that the Accept header needs to be part of the cache key. Is your server doing that?
Use cache:false in the $.ajax({...}) params. This adds a random value to the querystring so it ensures no caching happens.
use the following line to apply cache false to all ajax request made using jquery
$.ajaxSetup({ cache: false });
more options of ajaxSetup
Related
I'm new to web programming so bear with me. I've created a simple REST API in python flask, and am hosting it with Apache 2.4. I've tested it via cURL and it works. Now I'm trying to access it via a web interface with jQuery.
The REST api is at http://api.localhost and the website that accesses it is at http://localhost.
The code I'm using to try and do a POST looks like this:
$.ajax({
type: 'POST',
url: 'http://api.localhost/auth',
data: '{"username":"user1", "password":"abcxyz"}',
success: function(data) { console.log(data); alert('data: ' + data); },
contentType: "application/json",
dataType: 'json'
});
However, it seems the success function doesn't run. Looking in dev console (f12) I can see that instead of a POST to that URL, and OPTIONS HTTP request is made. My understanding is this is a Cross-Origin Resource Sharing (CORS) preflight check, to make sure it's OK for localhost to access api.localhost.
I've added the following lines to my apache config for api.localhost:
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"
It seems to be working to because the OPTIONS request returns a 200 (and no other data). However, there is no follow up. My understanding is since the server is saying it's OK for anyone to POST to api.localhost, that it should go ahead and do the POST next, but it doesn't.
Here are the preflight check request headers:
Host: api.localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://localhost
Connection: keep-alive
Cache-Control: max-age=0
Here are the response headers for that same request (remember, status 200):
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Origin: *
Allow: POST, OPTIONS
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 20
Content-Type: text/html; charset=utf-8
Date: Thu, 07 Dec 2017 00:17:08 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.29 (Debian)
Vary: Accept-Encoding
You can see that the server is saying any domain is fine (*) and that POST is OK. However, there is no follow up POST. What am I missing?
Thanks.
http://api.localhost/auth must also send Access-Control-Allow-Headers: content-type.
So to your Apache config, you also need to add this:
Header always set Access-Control-Allow-Headers "content-type"
That’s necessary because the contentType: "application/json" part of your frontend code adds a Content-Type: application/json header to the request, and any values for the Content-Type request header other than text/plain, application/x-www-form-urlencoded, or multipart/form-data will trigger browsers to send a CORS preflight OPTIONS request.
So if you have your http://api.localhost/auth server send back the Access-Control-Allow-Headers: content-type response header, that should cause the preflight to succeed, and so cause the browser to move on to making the POST request from your frontend code.
I try to make a POST call from a javascript client to a foursquare API called addvenue.
This the API endpoint documentation link.
But the server returns 405 - Method not allowed. Here is the snippet making the call
var postdata = {'oauth_token':$scope.access_token_foursquare,
'v':'20141217','name':'randomlisting',
'll':'44.3,37.2','m':'foursquare'};
var req = {
method: 'POST',
url: 'https://api.foursquare.com/v2/venues/add',
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
data: postdata
}
$http(req).then(function(response){
console.log(response);
});
Following is the Request and response packet for the above call.
Remote Address:103.245.222.185:443
Request URL:https://api.foursquare.com/v2/venues/add
Request Method:OPTIONS
Status Code:405 Method Not Allowed
**Request Headers**
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, authorization, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:api.foursquare.com
Origin:http://localhost:9000
Referer:http://localhost:9000/foursquare
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
**Response Headers**
Accept-Ranges:bytes
Access-Control-Allow-Origin:*
Connection:Keep-Alive
Content-Length:90
Content-Type:application/json; charset=utf-8
Date:Wed, 17 Dec 2014 12:15:15 GMT
Keep-Alive:timeout=10, max=50
Server:nginx
Tracer-Time:1
Via:1.1 varnish
X-Cache:MISS
X-Cache-Hits:0
X-Served-By:cache-sn87-SIN
I also studied about CORS issue. In my case the server is allowing all origins, as seen in the response headers. I am struck with this issue and could not proceed further.
Any help would be appreciated.
Thanks in advance.
Request Method:OPTIONS
The client is making a pre-flight OPTIONS request to the server.
An OPTIONS request is automatically made by the browser before making a non-simple (e.g. not a GET) cross domain (CORS) request.
The purpose of the OPTIONS request is a quick check with the server to ensure that the client is permitted to make the POST before actually making the POST. Thus the client makes 1 or 2 requests.
An OPTIONS request and if the OPTIONS request responds with success (not a 405) then make the POST.
The OPTIONS request is failing most likely because you have not stated in your server response that your server supports OPTIONS requests.
Add this header to your server response ..
Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS
Then it should all work.
See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests for more info
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.
In my FCGI app I want to make server-side response in a way to make the browser (want to use the majority of them) open "Save as" dialog box and actually save the file at user hard drive.
I fail w/ this(
Here is the dump of request/response received from Chrome:
Remote Address:192.168.1.69:80
Request URL:http://192.168.1.69/sunprint/sunweb.fcgi?GETPCBSDATAASFILE2SAVE
Request Method:GET
Status Code:200 OK
Request Headers
GET /sunprint/sunweb.fcgi?GETPCBSDATAASFILE2SAVE HTTP/1.1
Host: 192.168.1.69
Connection: keep-alive
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) >Chrome/34.0.1847.116 Safari/537.36
Referer: http://192.168.1.69/sunprint/PCBsVersions.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Query String Parameters
GETPCBSDATAASFILE2SAVE
Response Headers
HTTP/1.1 200 OK
Date: Mon, 05 May 2014 10:21:23 GMT
Server: Apache/2.2.22 (Ubuntu)
Cache-Control: no-cache, must-revalidate
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Content-Description: File Transfer
Content-Disposition: attachment; filename="SunSerialNumbers.txt"
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 227
Keep-Alive: timeout=5, max=81
Connection: Keep-Alive
Content-Type: text/plain
The content of my file is some set of printable ASCII symbols. BTW, should I encode the content in some way?
It seems that all the needed headers are present but browser still refuses to show the desired dialog box. Is the wrong combination of headers present?
To make a request i use the following code:
function sendCommandGetFile(url1) {
$.ajax({
url: url1,
type: "GET"
});
}
sendCommandGetFile("sunweb.fcgi?GETPCBSDATAASFILE2SAVE", function(data){});
Thanks a lot for help.
X-Requested-With: XMLHttpRequest
No set of HTTP headers is going to cause the browser to download a file it gets in response to a request using XHR.
You have three basic options.
Don't use XHR in the first place
Store the file data somewhere, give it a temporary URI, pass the URI back in the response, have the client side JS set location to that URI
Construct a data: scheme URI and have the client side JS assign it to location.
Unless you really need to sometimes return a file, and sometimes return data for JS to process (e.g. error messages) then option 1 is the best.
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