I'm feeling completely stupid because I've spent two hours solving task which should be very simple and which I solved many times before. But now I'm not even sure in which direction to dig.
I fail to fetch static content using ajax from local servers (Apache and Mongrel). I get responses 200 and 206 (depending on the server), empty response text (although Content-Length header is always correct), firebug shows request in red.
Javascript is very generic, I'm getting same results even here: http://www.w3schools.com/ajax/tryit.asp?filename=tryajax_first
(just change document location to 'http://localhost:3000/whatever')
So, it's probably not the cause.
Well, now I'm out of ideas. I can also post http headers, if it'll help.
Thanks!
Response Headers
Connection close
Date Sat, 01 May 2010 21:05:23 GMT
Last-Modified Sun, 18 Apr 2010 19:33:26 GMT
Content-Type text/html
Content-Length 7466
Request Headers
Host localhost:3000
User-Agent Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
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
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
Referer http://www.w3schools.com/ajax/tryit_view.asp
Origin http://www.w3schools.com
Response Headers
Date Sat, 01 May 2010 21:54:59 GMT
Server Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8l DAV/2 mod_jk/1.2.28
Etag "3d5cbdb-fb4-4819c460d4a40"
Accept-Ranges bytes
Content-Length 4020
Cache-Control max-age=7200, public, proxy-revalidate
Expires Sat, 01 May 2010 23:54:59 GMT
Content-Range bytes 0-4019/4020
Keep-Alive timeout=5, max=100
Connection Keep-Alive
Content-Type application/javascript
Request Headers
Host localhost
User-Agent Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
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
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
Origin null
UPDATED:
I've found a problem, it was about cross-domain requests. I knew that there are restrictions, but thought they're relaxed for local filesystem and local servers. (and expected more descriptive error message, anyway)
Thanks everybody!
It seems lake a caching problem only. Just delete cache inside of Internet Explorer and repeat your experiment. All HTTP GET requests will be cached. IE cache also ajax responses. If you don't like it you can append the URL with the text like '?p=blala'. Where 'p' is a name which will be interpret as a name of a parameter and text 'blala' must be unique in every request. Typically one use (new Date).getTime() construct to generate such 'blala'. IE will "think", that URL is new and will always send request to server.
UPDATED: Caching of static data will be made in all browsers, especially if Web server explicitly allow this: see Cache-Control: max-age=7200, public, proxy-revalidate is the response from server. Just try to go to http://www.w3schools.com/ajax/tryit.asp?filename=tryajax_first and modify the line
xmlhttp.open("GET","ajax_info.txt",true);
to
xmlhttp.open("GET","ajax_info.txt?p=" + (new Date).getTime(),true);
then click on "Edit and Click Me >>". Then if you click on "Change Content" button you will see in the HTTP traffic full data contain. I don't see any time 206 code. What it means if Response has "Accept-Ranges: bytes" and "Content-Range" like "bytes 0-4019/4020" inside of HTTP header you can read on http://benramsey.com/archives/206-partial-content-and-range-requests/
Related
I have developed a JavaScript code that sends periodically, every 500 msec, a GET request to an HTTP server, which answers to this request with text data in JSN format.
function get(theUrl, success, failure, commData)
{
commData = commData || {};
return fetch(theUrl)
.then(function(res)
{
if (!res.ok)
throw Error(res.statusText);
return res;
})
.then(function(res)
{
return res.text();
})
.then(function(html)
{
success(html, commData);
})
.catch(function(error)
{
failure(commData);
});
}
This javascript code is part of the resources (js, css, images) that are downloaded along with the index.html from the HTTP server.
The client receives answer from the server without any problem for some minutes. Suddenly, around 15 minutes after the download of the index.html, the browser inspector shows that the client starts receiving systematically error 403 ("forbidden") to the GET request. This happens with any browser (at least with Firefox, Chrome and IE/Edge). When the 403 error occurs, the failure() function of the above code sample is triggered.
I have monitored the connection with Wireshark, and I could see that, in spite of the 403 error, actually the HTTP server is still receiving the request and is sending the (correct) answer.
It looks like that in the browser there is some timer that is started when loading the home page (index.html), and which expires after some minutes, causing the fetch() API to fail with error 403.
I need that the periodical GET can works indefinitely, without limit of time, because its purpose is to monitor the state and retrieve important diagnostic data from an embedded system.
How can I solve it?
EDIT:
First of all; I have to correct the text and the title of this post, because the "forbidden" error is not 503, but 403. I apologize for the mistake.
Secondly, I am adding some useful information. The webserver is running on RTOS in a Concerto F28M36x processor. In order to make a simulation test and to debug more easily, I adapted the code of webserver in order to have it running on a Window machine, using the MSDN C++ HTTP API (https://learn.microsoft.com/en-us/windows/win32/http/http-server-api-overview). In this scenario, the HTTP server is running on the same computer of the client (localhost). Nevertheless, the behavior (with error 403) is exactly the same, as when the webserver is running in the embedded system. Here is what is shown by the browser inspector, when the GET request is successful (result=200):
GET http://localhost/readResults.cgi
Status 200 OK
Version HTTP/1.1
Transferred 308 B (174 B size)
Referrer Policy no-referrer-when-downgrade
Response header: (157 B)
Content-Length 174
Content-Type text/plain
Date Tue, 06 Apr 2021 11:00:39 GMT
Server Microsoft-HTTPAPI/2.0
Request headers (421 B):
Accept */*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
cache-control no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0
Connection keep-alive
expires Tue, 01 Jan 1980 1:00:00 GMT
Host localhost
pragma no-cache
Referer http://localhost/
Sec-GPC 1
User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
And this is shown by the browser inspector when the result is 403:
GET http://localhost/readResults.cgi
Status 403 Forbidden
VersionHTTP/1.1
Transferred 4.11 KB (3.95 KB size)
Referrer Policy no-referrer-when-downgrade
Response header: (157 B)
Cache-Control no-cache
Connection close
Content-Length 4047
Content-Type text/html; charset=UTF-8
Proxy-Connection close
Request headers (421 B):
Accept */*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
cache-control no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0
Connection keep-alive
expires Tue, 01 Jan 1980 1:00:00 GMT
Host localhost
pragma no-cache
Referer http://localhost/
Sec-GPC 1
User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
As one can see, with respect to the "good" case, in the "bad" case the following additional fields are present in the response header:
Connection: close
Proxy-Connection: close
Edit - since I am not receiving any answer, could somebody please suggest me a different forum where I can post this question?
Edit - just a gentle reminder. Any suggestion?
I have enable Access-Control-Allow-Origin on my apache webserver. I am able to load all requests on the first load. However, subsequent loading/refreshing of the pages would leave half of the requests failed, leaving an error of,
XMLHttpRequest cannot load http://***. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
In Chrome Developer Tool, under the Network tab, enabling "Disable Cache" removes this error.
I am using AngularJS $http to call my request, I have changed the cache option to true/false but this abnormality persist. For your information, I am also using an angular-cache module, https://github.com/jmdobry/angular-cache, I have tried enabling/disabling this too, but to no avail.
Here is a copy of the request header:
GET ***Valid_Url_With_Parameters** HTTP/1.1
Host: ********
Connection: keep-alive
Accept: application/json, text/plain, */*
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
I have a 2 different types response header with different HTTP status codes for the failed requests.
HTTP/1.1 200 OK
Content-Length: 564121
Content-Type: application/json
Server: Apache/2.2.15 (CentOS)
Vary: Accept
Last-Modified: Fri, 16 Sep 2016 12:41:41 GMT
Connection: keep-alive
Date: Fri, 16 Sep 2016 12:43:44 GMT
HTTP/1.1 206 Partial Content
Content-Type: application/json
Server: Apache/2.2.15 (CentOS)
Vary: Accept
Last-Modified: Fri, 16 Sep 2016 13:39:05 GMT
Content-Range: bytes 29200-29200/785592
Content-Length: 1
Connection: keep-alive
Date: Fri, 16 Sep 2016 14:20:48 GMT
It seems something to do with caching. The first time the page loads, all of the request have the correct access control header. Subsequent refresh/reload removes this header. How can I continue using caching and keep the access control header?
Edit:
Just to add on, I tried using Safari, the same abnormality appeared. It load on the first try but subsequent loading will throw a no access control allow origin error. However, this time, the response header in Safari shows blank.
Edit 2:
Abnormality appears in Firefox as well but not in Opera Beta version 40.0.2308.52. I am beginning to wonder if this is the cause of the browser. Access-Control-Allow-Origin header is present too.
Response Header in Opera
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Date: Sat, 17 Sep 2016 06:56:53 GMT
Server: Apache/2.2.15 (CentOS)
Vary: Accept
Transfer-Encoding: chunked
Edit 3:
I would like to add that the requests that I'm pulling is a large amount of data. I am pulling the last 7 days history of data, there are about 20 JSON files, each ranging from 500KB to 1000KB. I noticed that when I change the query parameter to pull in a small history of data, this error does not happen.
Any help is much appreciated.
One work around I've found is to dynamically generate a javascript file on the server as resource included into your page. This doesn't require AJAX the which gets blocked by CORS and can be cached.
We had this same problem in Chrome when returning a specific value in the 'Access-Control-Allow-Origin' header. We were able to solve it by also including Vary: Origin in the response headers.
It appears Chrome considers response headers, including 'Access-Control-Allow-Origin', as part of the cached response. So if it requests the same file from a different origin, that header from the cache will not match. But if you include Vary: Origin it lets Chrome know the response (just this one header in our case) will be different based on the Origin of the request.
This page on MDN explains it:
If the server sends a response with an Access-Control-Allow-Origin
value that is an explicit origin (rather than the "*" wildcard), then
the response should also include a Vary response header with the value
Origin β to indicate to browsers that server responses can differ
based on the value of the Origin request header.
I would recommend you to add chrome extension in your browser
Allow-Control-Allow-Origin: *
I am trying to upload a file and return a json response regarding properties(name, size etc) of the file. It works fine in all browsers except IE.
IE tries to download the JSON as a file !
I have IE10 and testing it on IE7 to 10 by changing browser mode and document mode from the debugger.
I am using asp.net mvc4, the file upload action have HttpPost attribute and i am returning json response using return Json(myObject);
And here are my http headers
Request
Key Value
Request POST /File/UploadFile/ HTTP/1.1
Accept text/html, application/xhtml+xml, */*
Referer http://localhost:63903/
Accept-Language en-NZ
User-Agent Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Content-Type multipart/form-data; boundary=---------------------------7dc1e71330526
Accept-Encoding gzip, deflate
Host localhost:63903
Content-Length 1377002
DNT 1
Connection Keep-Alive
Cache-Control no-cache
Response
Key Value
Response HTTP/1.1 200 OK
Server ASP.NET Development Server/11.0.0.0
Date Tue, 18 Dec 2012 23:44:19 GMT
X-AspNet-Version 4.0.30319
X-AspNetMvc-Version 4.0
Cache-Control private
Content-Type application/json; charset=utf-8
Content-Length 154
Connection Close
I tried a few suggestions but so far back to square one !
You will need to return the json as text/html since IE does not know what to do with application/json contents..
return Json(myObject, "text/html");
Not sure but it might work (and it would be more correct if it does) to use text/x-json
return Json(myObject, "text/x-json");
Even though this question is a few months old, I thought I'll add one more suggestion, just in case anyone else is using ASP.NET MVC 3 or 4 and runs into this problem.
In my experience, when IE attempts to download the Json response as a file all you have to do to correct the problem is to add a reference to jquery.unobtrusive to your view.
for example:
#Scripts.Render("~/Scripts/jquery.unobtrusive-ajax.min.js")
Once this is in place IE will no longer try to download the json response from a JsonResult controller action. No need to change the response type etc..
Here's the jQuery documentation:
http://api.jquery.com/load/
As mentioned there as an additional note:
Due to browser security restrictions, most "Ajax" requests are subject
to the same origin policy; the request can not successfully retrieve
data from a different domain, subdomain, or protocol.
Is there any way to bypass this limitation?
One way is to create a proxy page that requests the external page on the server. The implementation is dependent on the technology being used, but the idea is that you can then make an ajax call to your proxy page instead which will be on the same domain as the calling page.
Yes, there are several ways to get around this. But I would strongly suggest CORS (Cross-Domain Resource Sharing). CORS is the emerging standard for addressing cross-domain Ajax. This is replacing approaches such as JSONP (which has known security issues).
Unfortunately, CORS is not supported by older IE versions (6-9), but there are established polyfills for browsers which do not natively implement CORS. easyXDM is one such polyfill.
At a basic level, below is a sample request (from the MDN link above), where the browser generates a request with the Origin header, indicating the domain of the request, which is validated by the endpoint:
GET /resources/access-control-with-credentials/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/credential.html
Origin: http://foo.example
Cookie: pageAccess=2
An Ajax endpoint supporting CORS may respond with the appropriate headers, which the browser validates. See Access-Control-Allow-Origin and Access-Control-Allow-Credentials in this example:
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT
Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2
X-Powered-By: PHP/5.2.6
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
The browser may also send a pre-flight (using the OPTIONS verb) which can indicate to the server what headers or verbs the Ajax call will use. The pre-flight is actually a separate call from the primary Ajax call, but is only invoked under certain conditions.
Many web servers (IIS, Apache) support CORS through modules. The servers will require configuration to white-list origins, allowed verbs, headers, etc. Wildcarding can also be used but is not recommended.
i am including JS on domain1 form domain2
<script type="text/javascript" src="http://www.domain2.com/script.js"></script>
that script doesn onload and on button click a JSONP request to domain2
$.getJSON( 'http://www.domain2.com/process?callback=?',
function(data){
if ( data ) processData( data );
}
);
and then displaying the data on domain1.
So here is my problem:
The getJSON request doesnt send cookies to the domain2.
The weirdest thing is that it does send the cookies half a day and the other half not. :-)
This is how the request looks like when it doesnt work:
Request details
GET /ajax/embed-user-library?detail=98&callback=jsonp1312398534998 HTTP/1.1
User-Agent: Opera/9.80 (Windows NT 6.1; U; en) Presto/2.9.168 Version/11.50
Host: www.floowie.com
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en,sk-SK;q=0.9,sk;q=0.8
Accept-Encoding: gzip, deflate
Referer: http://www.sokker.cz/en/test2
Connection: Keep-Alive
Response details
HTTP/1.1 200 OK
Date: Wed, 03 Aug 2011 19:06:51 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.5-0.dotdeb.1
Set-Cookie: SESSID=64292b70dc28d7c6c9f13f70070353d8; path=/; domain=.floowie.com
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Content-Length: 34
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: application/json
And this when it works(nothing changed in the scripts):
Request details
GET /ajax/embed-user-library?detail=99&test=1&callback=jsonp1312398534999 HTTP/1.1
User-Agent: Opera/9.80 (Windows NT 6.1; U; en) Presto/2.9.168 Version/11.50
Host: test1.floowie.com
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en,sk-SK;q=0.9,sk;q=0.8
Accept-Encoding: gzip, deflate
Referer: http://www.sokker.cz/en/test2
Cookie: __utma=254918925.1489796832.1301725317.1312260335.1312298033.44; __utmz=254918925.1312298033.44.11.utmcsr=sokker.cz|utmccn=(referral)|utmcmd=referral|utmcct=/en/test2; lang=en; FLWSESSID=ddd1bc696f83f5a70b5f0f3ae30b4691; __utma=121955676.1030804516.1282595153.1312390656.1312397285.194; __utmb=121955676.8.10.1312397285; __utmc=121955676; __utmz=121955676.1312397285.194.21.utmcsr=floowie.crmserver.cz|utmccn=(referral)|utmcmd=referral|utmcct=/index.php
Connection: Keep-Alive
Response details
HTTP/1.1 200 OK
Date: Wed, 03 Aug 2011 19:07:45 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.5-0.dotdeb.1
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Content-Length: 20
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: application/json
Did someone see such a behaviour?
Is it solvable?
Thank you
If you want to use AJAX petitions over different domains/subdomains you have to implement Cross Origin Requests.
References:
http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
https://developer.mozilla.org/en/http_access_control
Examples:
http://arunranga.com/examples/access-control/
Your server needs to send this headers:
Access-Control-Allow-Origin: test1.floowie.com
Access-Control-Allow-Credentials: true // allow cookie/session credentials
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
You can return the Access-Control-Allow-Origin globally or set specifically dependent of your input Origin ($_SERVER['HTTP_ORIGIN']) request header. Also apply for Access-Control-Allow-Methods.
You must implement the OPTIONS petition. Before the first AJAX call, modern browsers call that URL with an OPTIONS method to retrieve the above headers.
Ok this is the first part, the second is with jQuery. Read very carefully this page: http://api.jquery.com/jQuery.ajax/
You will need to add some options to every AJAX call, you can do it globally:
$(document).ajaxSend(function (event, xhr, settings) {
settings.xhrFields = {
withCredentials: true
};
});
Or specific:
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
This issue made ββme lose many hours... hope it helps.
Note that you won't need to set your cookie domain as ".floowie.com" if you want.
You must properly implement CORS requests with credentials to send and receive cookies via Ajax. See developer.mozilla.org, specifically under the section titled "Requests with credentials."
First off, here is a simple CORS Ajax request with credentials, using jQuery 1.5.1+:
$.ajax({
url: "http://www.domain2.com/process",
xhrFields: {
withCredentials: true
}
}).done(function (data) { console.log(data); });
Note the withCredentials flag in the xhrFields. This flag tells the browser to send cookies with the request for the external domain, not the origin domain. In your case, cookies for www.domain2.com will be sent, and you will have access to them server-side.
On the server-side, you need to add certain headers to the response:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: www.domain1.com
Important: requests with credentials cannot set the Access-Control-Allow-Origin header to global (Access-Control-Allow-Origin: *). It must specify domains (Access-Control-Allow-Origin: www.domain1.com).
It's obviously better if you specify a domain for the Access-Control-Allow-Origin header. But if you don't know or care where the CORS request is coming from, you could use the Origin header from the request and simply set the Access-Control-Allow-Origin header of your response to that. In C#, this is how we did this:
this.Response.AddHeader("Access-Control-Allow-Origin", this.Request.Headers["Origin"]);
After doing all of this, cookies that you set server-side will be sent back with the response, and the browser will be able to properly handle them and insert them into the browser's cookie store for www.domain2.com. And any subsequent CORS requests you send will send these cookies in the request as well.
If you are sending a request other than with the GET, POST, or HEAD methods, you will need to implement Preflighted requests (see under section titled "Preflighted 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:
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.
It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
Side-note about IE8 and IE9:
The Ajax call above will fail in IE8 and 9. I included the JS file from MoonScript/jQuery-ajaxTransport-XDomainRequest on my page, and this automagically allowed CORS requests to work in those old IE versions. But sadly, the XDomainRequest object that MS created for IE8 and 9 does not allow cookies to be sent or received. (see this MSDN blog post for more information)
You have different hosts. In the first example the host is "Host: www.floowie.com". In the second it is "Host: test1.floowie.com".
I'm guessing that the cookies are originally set by 'test1.floowie.com' and you haven't specified that they should be available to '.floowie.com' (i.e. the whole domain and all subdomains).
Can you post the code that sets the cookies in the first place?
If you get this fixed, it should at least show consistent behaviour. However, IE will probably still not pass cookies across subdomains. That's what I'm wrestling with at the moment, which is how I can across your question.