I'm implementing a simple REST service with the WCF Web API and attempt to set HTTP headers in order to cache responses.
For a simple GET like this
http://localhost:49302/my/2
the response headers look like this:
Server: ASP.NET Development Server/10.0.0.0
Date: Tue, 24 Jan 2012 18:18:44 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 233
Cache-Control: max-age=120
Vary: Accept
Expires: Tue, 24 Jan 2012 18:20:44 GMT
Last-Modified: Tue, 24 Jan 2012 18:18:15 GMT
Content-Type: application/xml; charset=utf-8
The intent is that the client should cache the resource for two minutes.
However, using the WCF Web API Test Client, the behavior is inconsistent across various browsers:
In Firefox (9.0.1) the request is cached, and first after two minutes is a new version of the resource displayed. This behavior is as expected.
In Chrome (16.0.912.77 m) the cache headers aren't respected at all. A new version of the resource is being fetched for every GET request. This behavior is not expected (by me, at least).
In Internet Explorer (9) the behavior is the same as in Chrome.
Why doesn't Chrome and IE respect the cache headers?
Is it a bug in the WCF Web API Test Client?
Caching is hard to get right. The fact that a browser may ignore cache directives certainly doesn't help.
According to this document IE never cached any request with a Vary header containing anything but Accept-Encoding and User-Agent
If I test this with a 15 seconds cache period and I just set the MaxAge and MustRevalidate it seems to work fine with IE9, FireFox and Chrome.
Web API HttpResponseMessage:
result = new HttpResponseMessage<Book>(book);
result.Headers.CacheControl = new CacheControlHeaderValue();
result.Headers.CacheControl.MaxAge = TimeSpan.FromSeconds(15);
result.Headers.CacheControl.MustRevalidate = true;
return result;
Response headers:
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 25 Jan 2012 09:13:32 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 98
Cache-Control: must-revalidate, max-age=15
Content-Type: application/json; charset=utf-8
Connection: Close
I am not sure the MustRevalidate is really required but it is recommended to use it. See the specs here.
Test to replace localhost with "real domain" so the WCF Test Client or Chrome/IE doesnt have any special tricks for localhost.
Related
I have set all headers that I know of to disable caching (even disabling ETAG) on my server, yet Safari still occasionally (about 50% times) caches my requests.
Workflow
I am implementing oauth 1, so:
Browser makes GET /api/user request
Server returns 405
Browser redirects to 3rd party website to authenticate
Browser is redirected to api/callback which stores some info into cookie.
Browser is redirected back to original route.
Browser makes GET /api/user request which should be successful, however it gets 405 served from disk cache instead.
Request summary from Safari Network Inspector
Summary
URL: http://localhost:3000/api/user
Status: 405 Method Not Allowed
Source: Disk Cache
Request
No request, served from the disk cache.
Response
Transfer-Encoding: Identity
Content-Type: application/json; charset=utf-8
Pragma: no-cache
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0
Vary: Cookie, Accept-Encoding
Date: Wed, 23 Jan 2019 11:34:23 GMT
Content-Encoding: gzip
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Connection: close
x-powered-by: Express
Conclusion
I have no idea what's wrong and I will greatly appreciate any help. My
Safari version is 12.0.2. I wasn't able to replicate this issue with Chrome.
Use Vary: *. This magically solved my problem.
This answer helped me: https://stackoverflow.com/a/2068353/1364158
Alternatively, you can really force browser to load a new version of request by including some meaningless random query arg in your url, e.g. /api/user?ts=18284
Given this server response:
HTTP/1.1 200 OK
Date: Fri, 23 Mar 2018 12:17:57 GMT
Access-Control-Allow-Origin: http://localhost:8888
Vary: Origin
Access-Control-Allow-Credentials: true
Set-Cookie: key=value;Version=1
Content-Type: application/json
Content-Length: 276
I thought this cookie (key=value) would be stored on client side and I would be able to view it from Chrome DevTools. However I don't see any cookie there. And the cookie is not included on the further requests made after the requested shown above. So I guess it's not stored.
To store the cookies is not the default behavior of the browser?
I've tried setting the cookie property httpOnly to true with the same results.
How can force the browser to store the cookie without using JS and including it on further requests without any JS interaction?
I am sending events from Winform application to Universal Analytics via Measurement protocol and I use fiddler to inspect the request and response. Everything seems to be OK, but no events appears in Universal Analytics.
My app request:
POST http://www.google-analytics.com/collect HTTP/1.1
Host: www.google-analytics.com
Content-Length: 112
Expect: 100-continue
v=1
&tid=UA-44974825-1
&cid=1aba0888-732f-4690-9a91-d906c94a4a23
&t=exception
&exd=NullReferenceException
&exf=1
Server response:
HTTP/1.1 200 OK
Pragma: no-cache
Expires: Mon, 07 Aug 1995 23:30:00 GMT
Cache-Control: private, no-cache, no-cache=Set-Cookie, proxy-revalidate
Access-Control-Allow-Origin: *
Last-Modified: Sun, 17 May 1998 03:00:00 GMT
X-Content-Type-Options: nosniff
Content-Type: image/gif
Date: Fri, 18 Oct 2013 13:54:39 GMT
Server: Golfe2
Content-Length: 35
Alternate-Protocol: 80:quic
GIF89a�����������,�������D�;
Your request is missing the app name parameter, &an, which is required for sending data to app profiles in Google Analytics via the Measurement Protocol.
The requirements for sending app data to Google Analytics via the Measurement Protocol are documented here:
https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide#apptracking
The GA endpoint will always return 200, even if the request is missing required parameters.
I discovered another reason why no data is being collected: I hadn't upgraded my property to Universal Analytics, yet! Doh!
The root problem here is that you are not formatting your request properly. You need to format your POST body like any other application/x-www-form-urlencoded encoded POST body, all on one line:
v=1&tid=UA-44974825-1&cid=1aba0888-732f-4690-9a91-d906c94a4a23&t=exception&exd=NullReferenceException&exf=1
For anyone who lands here looking for solution to something similar, check this tool: Hit builder to validate the payload data.
I was facing the same issue this tool helped.
(Not sure if this debug tool was available then when this question was posted)
I'm trying to add HTTP Conditional Get functionality to the first page of a mobile site. However, what I'm seeing is making me think that Safari simply doesn't support HTTP Conditional Get for the first document it loads.
I tested this by making a new Rails 3.2.13 application, with one action that looks like this:
def index
last_modified = Date.today
etag_obj = "something something"
fresh_when last_modified: last_modified, etag: etag_obj, public: false
end
The request headers contain both an Etag and Last-Modified, as expected:
[cache_test]$ curl -I http://localhost:5000/test
HTTP/1.1 200 OK
Etag: "79b547467286b3e20fad13f73fc1bf78"
Last-Modified: Wed, 24 Apr 2013 00:00:00 GMT
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=0, private, must-revalidate
X-Ua-Compatible: IE=Edge
X-Request-Id: 8ace0b71533b2bc036bd84b12289cda6
X-Runtime: 0.012269
Server: WEBrick/1.3.1 (Ruby/1.9.3/2012-04-20)
Date: Wed, 24 Apr 2013 21:06:49 GMT
Content-Length: 0
Connection: Keep-Alive
Set-Cookie: _cache_test_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJTM0NWRjNDgyZGQwNWJmMGZkNmIzNmY4NjVmNWEzMDkwBjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMTlYK0VrMERGdEsvOVlzbVJ5N1FPQlZXVDRwak9zQ3QzS3ZXZ1pvbnJocjg9BjsARg%3D%3D--0902ae8a505527bd49d969753ddf1d2bd4c716eb; path=/; HttpOnly
On Firefox 20.0 and Chrome 26.0.1410.65 this acts like I expect: On the second load, the browser sends If-Modified-Since and If-None-Match in the request, and receives a 304 Not Modified.
However, it's not doing this on Safari. On Safari it sends neither If-Modified-Since nor If-None-Match, and as you'd expect, it then fully reloads the page from the server. I am seeing this on Safari 6.0.3 on my MacBook Pro, Safari in the iOS Simulator using an iPhone with iOS 6.1, and on an iPad Mini with iOS 6.1.3.
And what's really strange about this is that Safari clearly supports Conditional Get for subsequent requests (CSS, JS, images, etc) -- I can see them clearly after the main HTML page comes through. But I can't for the life of me figure out how to get Safari to make a Conditional Get request for the first document.
So, I guess my question is two parts:
Am I missing something obvious? Because it actually seems a little crazy that Safari would act this way by design. But maybe I'm expecting too much from Apple here.
If I'm not missing something obvious, does anybody know of any workarounds?
I have an RSS feed. When I browse to the feed with Fiddler Web Debugger open, Fiddler throws this error at me:
Chunked body did not terminate properly with 0-sized chunk.
The response from the server that triggered the error looks like this:
HTTP/1.1 200 OK
Date: Tue, 22 Jan 2013 21:00:49 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Content-Length: 30985
<rss version="2.0">
<channel>
... etc
The owner of the RSS is reporting problems when trying to submit the site to RSS aggregators.
I tried to validate the rss here: http://validator.w3.org/appc/. The response was this:
IncompleteRead(30985 bytes read) (IncompleteRead; misconfigured server?)
However, if I browse to the rss and copy past the code into this validator: http://validator.w3.org/appc/#validate_by_input, then everything validates correctly.
How do I correct this? This is a C# ASP.NET webforms project running on .NET 3.5 in IIS6.
Update
It appears that I was using Fiddler incorrectly. After unchcking the Decode option, here is the server response:
HTTP/1.1 200 OK
Date: Tue, 22 Jan 2013 21:22:03 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Transfer-Encoding: chunked
Cache-Control: private
Content-Type: text/xml; charset=utf-8
7909
<rss version="2.0">
<channel>
... etc
The data you posted above is not what the server sent. The response from the server contained a HTTP Header Transfer-Encoding: chunked but your data was not properly in the HTTP-chunked encoding format.
Please update your question with the actual data, as captured by Fiddler, making sure the Decode option in Fiddler's toolbar is NOT checked.
(As to the root cause of the problem, did you mistakenly call Response.Close()? See this article for an explanation of why that's the incorrect way to complete a HTTP response.)