I really hope someone has some ideas. I have set up my web config to cache images for 30 days.
web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="30.00:00:00" />
</staticContent>
</system.webServer>
</configuration>
Yet when I request the page with IE and checkout network traffic this is what I see:
Request Header:
Key Value
Request GET http://www.xx.com/Content/Icons/login.png HTTP/1.1
Accept image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5
Referer http://www.selftestware.com/
Accept-Language en-US
User-Agent Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept-Encoding gzip, deflate
Host www.xx.com
If-Modified-Since Wed, 24 Aug 2011 15:48:10 GMT
If-None-Match W/"0195d397562cc1:0"
Proxy-Connection Keep-Alive
Pragma no-cache
Cookie __utma=xx
Response:
Key Value
Response HTTP/1.1 200 OK
Cache-Control public,max-age=2592000
Content-Type image/png
Last-Modified Wed, 24 Aug 2011 15:48:10 GMT
Accept-Ranges bytes
ETag W/"0195d397562cc1:0"
Server Microsoft-IIS/7.5
X-Powered-By ASP.NET
Date Wed, 24 Aug 2011 10:39:14 GMT
Content-Length 727
Should it not send a 304 (not modified). I just can't understand what's wrong here.
Your request header was sent a "Pragma: no-cache" which means told the server not to cache this request. That's why your server response HTTP 200 rather than HTTP 304.
This "Pragma: no-cache" was sent by the browser. If you press Ctrl+F5 hotkey or configured your browser not to cache anything will cause this result. You can try to create a blank page that contains a link to this cached page, then click the link on it. You'll see this page been cached.
Related
We seems to be having an issue with a css file caching on the client. I generally stop this from causing issue by adding a version number to the file, i.e.
<link href="Default.css?4.31.0.17051" rel="stylesheet" type="text/css">
But in this circumstance this isn't working and I don't understand why.
The version number was incremented last night from 4.30.0.xxxxx to 4.31.0.17051
Some users, and I've seen it myself, are getting a HTTP 304 response. What's strange is if I inspect it using the IE dev tools it shows a HTTP 304, if I fire up fiddler it doesn't show any request at all.
Content caching is not enabled on the server.
Here's the HTTP header if I do a ctrl-f5:
HTTP/1.1 200 OK
Content-Length: 45861
Content-Type: text/css
Last-Modified: Tue, 23 Jul 2013 14:19:40 GMT
Accept-Ranges: bytes
ETag: "0a61aabaf87ce1:bdba"
Vary: Accept-Encoding
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Tue, 30 Jul 2013 16:05:54 GMT
So:
why don't I see this in fiddler? is it not sending the request at all as this question suggests (https://stackoverflow.com/a/8958279/542251)
Why isn't this cache control (i.e. adding the ?4.31.0.17051 to the file) working?
EDIT
I've now touched the file, to update the Last-modified date but it's still not requesting it.
So the page is returning a HTTP 200, so this isn't the page caching as suggested below:
Request:
GET http://www.mysite.com/Agent/Hotel HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Referer: http://www.mysite.com/Agent/Flights
Accept-Language: en-GB
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept-Encoding: gzip, deflate
Host: www.mysite.com
Connection: Keep-Alive
Response:
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 53184
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
X-AspNetMvc-Version: 3.0
Date: Wed, 31 Jul 2013 08:33:25 GMT
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href="Default.css?4.31.0.17051" rel="stylesheet" type="text/css" />
.........
As noted in my answer that you cited, the F12 Tools can show a HTTP/304 when the response was really served from the cache. If you don't see the request in Fiddler, it wasn't sent over the network.
Are you sure that the page that refers to the CSS file wasn't pulled from the cache? If it were, then you'd still have the old URL reference. (Look carefully at the CSS request's URL in the F12 tools, as the URL will be accurate even if the "304" was not).
Two points:
- What does "Why isn't this cache control working?" mean? Your HTTP-response headers don't include any Cache-Control directives.
- Changing the Last-Modified date on the server obviously isn't something the client will know about unless it actually issues a Conditional GET request to the server.
So I got a solution but not necessarily an answer.
In the end I updated the tag on the site to:
<link href="Default.css?v=4.31.0.17051" rel="stylesheet" type="text/css">
I'm not sure if adding the v= turning it into a valid querystring was the solution or whether it was just the fact that I altered the URL again solved this issue.
I haven't been able to replicate this issue in staging so I don't really know how or why this started happening.
I have user-submitted files that I'm trying to upload in 10 MB chunks. I'm currently using raw XMLHttpRequest (and XDomainRequest) to push each individual slice (File.prototoype.slice) on the front end. The back end is Nginx using the upload module.
Just for reference, here's the synopsis of how I'm using slice:
element.files[0].slice(...)
I understand the cross-browser prefixed methods webkitSlice and mozSlice and all that.
The problem I have is with actually making the cross-domain request. I'm uploading from server.local to upload.server.local. In Firefox, the options request goes through fine and then the actual post fails. In Chrome and Opera, the options request fails with
OPTIONS https://URL Resource failed to load
Here are the headers from Firefox:
Request Headers
OPTIONS /path/to/asset HTTP/1.1
Host: upload.server.local:8443
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:18.0) Gecko/20100101 Firefox/18.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
Origin: https://server.local:8443
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-disposition,content-type,x-content-range,x-session-id
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Response Headers
HTTP/1.1 204 No Content
Server: nginx/1.2.6
Date: Wed, 13 Feb 2013 03:27:44 GMT
Connection: keep-alive
access-control-allow-origin: https://server.local:8443
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: x-content-range, origin, content-disposition, x-session-id, content-type, cache-control, pragma, referrer, host
access-control-allow-credentials: true
Access-Control-Max-Age: 10000
The actual post request never leaves the browser. Nginx access logs never see the post. The browser halts it for some reason. How do I unravel why this post is being blocked?
Chromium 24
Firefox 18
Opera 12.14
I've verified all browsers support CORS properly here.
By pointing my uploads to https://cors-test.appspot.com/test, I have confirmed that the problem is definitely with the server-side headers.
The POST won't leave the browser if the preflight check does not return sufficient permissions and thus the POST request is not fully authorized. The request/response included in the question does look sufficient to me.
Are you sure you are setting withCredentials = true in your XMLHttpRequest?
Are you sure that you have valid (not self-signed) SSL certificates on your servers? The HTTPS might fail the CORS check even if you have added an exception for browsing the site with an invalid certificate.
Have you tried emptying your cache? You have Access-Control-Max-Age: 10000 set in your response headers. That's close to 3 hours. I know you've been working on this longer than that but while testing especially, set that header to zero instead so you don't go crazy with browser caching of old access permissions.
In general I'd start with going as permissive as possible with the CORS headers and slowly ratcheting up the the security to see where it fails. However, this is not completely straightforward. For example, according to the MDN documentation on CORS,
When responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: *
When I send the request part of your question to https://cors-test.appspot.com/test, I get back the following:
HTTP/1.1 200 OK
Cache-Control: no-cache
Access-Control-Allow-Origin: https://server.local:8443
Access-Control-Allow-Headers: content-disposition,content-type,x-content-range,x-session-id
Access-Control-Allow-Methods: POST
Access-Control-Max-Age: 0
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Content-Type: application/json
Content-Encoding: gzip
Content-Length: 35
Vary: Accept-Encoding
Date: Thu, 23 May 2013 06:37:34 GMT
Server: Google Frontend
So you can start from there and add more and more security until it breaks to figure out what is the culprit.
I'm trying to get YSlow to give me an A on the "Add Expires header" section by setting the web.config file.
I've been looking around and this is what I put in based on what's out there:
<staticContent>
<clientCache httpExpires="15.00:00:00" cacheControlMode="UseExpires"/>
</staticContent>
</system.webServer>
This is what I'm seeing in Firebug:
Response Headers
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Sun, 28 Aug 2011 13:54:50 GMT
X-AspNet-Version: 4.0.30319
Cache-Control: private
Content-Type: image/jpeg
Content-Length: 24255
Connection: Close
Request Headersview source
Host localhost:50715
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0
Accept image/png,image/*;q=0.8,*/*;q=0.5
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://localhost:50715/MySite/SiteHome.html
Pragma no-cache
Cache-Control no-cache
However, when I look at it in Firefox, Yslow is still giving an F on this, even after a Crtl-F5
What am I missing?
Thanks.
From .NET Daily, I successfully applied this to a PHP site on IIS. It sets the max age to 30 days from now, rather than having to specify an explicit date.
Add this to your web.config file:
<system.webServer>
<staticContent>
<clientCache cacheControlMaxAge="30.00:00:00" cacheControlMode="UseMaxAge"/>
</staticContent>
</system.webServer>
This configuration satisfies both PageSpeed "Leverage browser caching" and YSlow "Add Expires headers". YSlow requires a value greater than 7 days. PageSpeed requires between 30 days and 1 year.
From the clientCache documentation
The value for the httpExpires attribute must be a fully-formatted date and time that follows the specification in RFC 1123. For example:
Fri, 01 Jan 2010 12:00:00 GMT
So, if you want to use the http expires headers for your static content, set it like this:
<staticContent>
<clientCache cacheControlMode="UseExpires" httpExpires="Sun, 1 Jan 2017 00:00:00 UTC" />
</staticContent>
Update (to above comments): This will most probably still not work in the built in VS server. I'm not sure if it supports expires headers at all. AFAIK this is an IIS setting.
I believe the recommendation is to add expires on static content rather than ASPX pages. Make sure you are checking the request headers for static content such as images and not the ASPX file.
Check out :
http://developer.yahoo.com/performance/rules.html
I have a request to the server which looks like this:
http://localhost/Combine.aspx/flag/file1.js,file2.js,file3.js
I have also tried this:
http://localhost/Combine.aspx/flag/value/file1.js/file2.js/file3.js
It simply combines the three files which it was given: this works fine.
Upon the first request from Firefox, the page displays correctly. When the page is refreshed again, the content looks like this:
��������`I�%&/m�{J�J��t��`$�����iG#)�*��eVe]f#�흼��{���{��;�N'
In that case, no request is made to the server, the file is only retrieved from the firefox cache, as far as I can tell.
If I force-refresh the page with Control-F5, the page looks normal again.
Here is the request and response (in firebug) with Control-F5 (works):
Response
Cache-Control public
Content-Type application/javascript; charset=utf-8
Content-Encoding gzip
Expires Sun, 26 Feb 2012 02:57:26 GMT
Last-Modified Fri, 07 Jan 2011 21:08:54 GMT
Etag CLYvZwbFmainWEMi8h-6x-zNEIQ1
Vary Accept-Encoding
Server Microsoft-IIS/7.5
Set-Cookie auth=longstring; path=/
X-AspNet-Version 2.0.50727
X-Powered-By ASP.NET
Date Thu, 03 Mar 2011 02:57:26 GMT
Content-Length 918
Request
Host localhost
User-Agent Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.14) Gecko/20110218 Firefox/3.6.14
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
Cookie auth=longstring
Pragma no-cache
Cache-Control no-cache
Here is the same with just F5 (doesn't work):
Response:
Cache-Control public
Content-Type application/javascript; charset=utf-8
Content-Encoding gzip
Expires Sun, 26 Feb 2012 02:57:26 GMT
Last-Modified Fri, 07 Jan 2011 21:08:54 GMT
Etag CLYvZwbFmainWEMi8h-6x-zNEIQ1
Vary Accept-Encoding
Server Microsoft-IIS/7.5
X-AspNet-Version 2.0.50727
X-Powered-By ASP.NET
Date Thu, 03 Mar 2011 03:01:31 GMT
Content-Length 1533
Request:
Host localhost
User-Agent Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.14) Gecko/20110218 Firefox/3.6.14
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
Cookie auth=longstring
The only thing that I can tell is different is the Content-Length (which is likely causing the corruption), but since it never hits the server, I have no control over it.
What could be causing this?
Edit:
This happens on IE8 as well, but instead of viewing a corrupt file, it downloads the corrupt file. No request is ever made to the server (set a breakpoint in visual studio).
As for chrome, when viewing the url directly, a request to the server is made every time, and it works every time. I believe, though, that if it were included in a tag, it would behave similar to Firefox.
Oh, and also:
If I turn off the Expires header (which is one of the flags in the URL), everything works fine.
Edit 2:
I was able to work around this by not sending both an Expires and ETag header, only one or the other. I have no clue why an ETag header would cause such corruption, though.
It is because of your IIS configuration. Adjust IIS as ASP 4.0 Classic, not Default Application Pool
I have a situation where my (embedded) web server is sending Expires header, but the browser does not seem to respect the header setting, i.e., if I refresh the page, the browser requests the resources that are supposed to be cached. Following are the headers that are getting exchanged:
https://192.168.1.180/scgi-bin/ajax/ajax.cgi
GET /scgi-bin/ajax/ajax.cgi HTTP/1.1
Host: 192.168.1.180
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)
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: 300
Connection: keep-alive
Cache-Control: max-age=0
HTTP/1.x 200 OK
Date: Wed, 24 Jun 2009 20:26:47 GMT
Server: Embedded HTTP Server.
Connection: close
Content-Type: text/html
----------------------------------------------------------
https://192.168.1.180/scgi-bin/ajax/static.cgi?fn=images/logo.jpg&ts=20090624201057
GET /scgi-bin/ajax/static.cgi?fn=images/logo.jpg&ts=20090624201057 HTTP/1.1
Host: 192.168.1.180
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)
Accept: image/png,image/*;q=0.8,*/*;q=0.5
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: 300
Connection: keep-alive
Referer: https://192.168.1.180/scgi-bin/ajax/ajax.cgi
Cache-Control: max-age=0
HTTP/1.x 200 OK
Date: Wed, 24 Jun 2009 20:26:47 GMT
Server: Embedded HTTP Server.
Connection: close
Expires: Wed, 1 Jun 2011 20:00:00 GMT
Content-Type: image/jpg
----------------------------------------------------------
The ajax.cgi returns an html page with a logo graphic (via the static.cgi script), which I'd like cached, but the browser is asking for the logo on every refresh.
The browser ignores the Expires header if you refresh the page. It always checks whether the cache entry is still valid by contacting the web server. Ideally, it will use the If-Modified-Since request header so that the server can return '304 Not modified' if the cache entry is still valid.
You're not setting the Last-Modified header, so the browser has to perform an unconditional GET of the content to ensure that it is up to date.
Some rules of thumb for setting Expires and Last-Modified are described in this blog post:
http://blog.httpwatch.com/2007/12/10/two-simple-rules-for-http-caching/
What are you doing in your browser? I looks like you click the reload button or even something like shift+Reload. Normally, the browser wouldn't send a Cache-Control: max-age=0 header. That means the browser has thrown away the cached image and wants to get it again.
If you just navigate to another page and then back again, the browser should respect your Expires header.
Additionally, you could add a Cache-control: public header to your response. That allows proxies and the browser explicitly to cache the image.
Any errors in your https certificate will cause the browser to not respect your headers.
Try it without https and see if it works over plain http.
See this answer https://stackoverflow.com/a/17716911
The CGI script looks like it has a timestamp parameter...this isn't changing, is it? The browser should be treating each unique URL as a different object in the cache, so if that is updating with every request, it won't match with the cached image.
Additionally, the Expires field is not exactly in RFC 1123 format, because you need two digits for the date. This may or may not be an issue, but it's something to check. The browser is including Cache-Control: max-age=0, which indicates that it believes its cache to be potentially out of date.
Once the server gets this validation request, it can return 304 (Not Modified), or 200 (OK), as it is doing currently.