htaccess mod_headers for no-caching - apache

We have an application that allows users to add/edit/replace/delete content (text, images, swfs, mp3s, etc). We want the admins to always have the latest updated files by using a no-cache header and when a user runs the application, everything gets/uses the cache.
I have looked into solutions and have tried using html meta tags like:
<meta http-equiv="expires" content="0" />
<meta http-equiv="cache-control" content="no-cache, no-store" />
<meta http-equiv="pragma" content="no-cache" />
But that doesn't seem to be a good solution as this happens after the headers are created and doesn't change the media (images, swfs, mp3s, etc) headers.
I wanted to use apache to set the headers and came across this code for this site:
<filesMatch "\.(html|htm|js|css)$">
FileETag None
<ifModule mod_headers.c>
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</ifModule>
</filesMatch>
This seems to be a great solution, however the only real difference between when we need it cached and when it shouldn't be cached is the URL (preview.jsp vs run.jsp), so we can't match it by file type as most files are the same.
Does anyone have a good solution for this type of scenario?
Thanks.
EDIT:
Preview.jsp and run.jsp basically are the same only with different jsp and js processing. They read in the same content and media through an iframe. For example, they each look like:
<%
//Some JSP
%>
/* HTML Headers, JS, ETC */
<iframe id="contentFrame" seamless="1" src="http://somedomain.com/template.html"></iframe>
/* End HTML */
preview.jsp and run.jsp appear in the same directory and use all the same resources. I am looking for a solution to have preview.jsp not to cache anything and run.jsp to cache things.
Server is setup with Apache Tomcat.

A combination of SetEnvIf and Header might do the trick:
# Image, CSS and JavaScript requests normally contain the Referer header
# which tells apache which page is requesting the resource
# Use SetEnvIf directive to set a flag for internal uses
SetEnvIf Referer preview\.jsp force_no_cache
# Header directive optionally accepts env= argument
# If present, the directive is fired if the flag is set
Header unset ETag env=force_no_cache
# repeat for other headers

You can set up corresponding headers in your Java servlet. Apache mod_headers is mostly supposed to work for static resources, managed by Apache. While everything that is provided by application servers is managed on the AS side.
Usually, you can use Filters for this purpose. Here is an example: http://www.tidytutorials.com/2009/11/adding-headers-to-requests-in-filters.html

Related

No cache HTML file apache Centos7 (VueJS / Quasar Build)

We've build an application with vueJs using Quasar Framework
But after each rebuild (with quasar build command executed by a gitlab runner) our main index.html file isn't reload properly by client's browser (seems it's more chrome than other browser who's keeping the index.html in cache)
In our application we have many css and js file named like that for example :
app.34456435fdfe.js
vendor.4325gfd.js
runtime.ksdj424.js
The app file js and the runtime file js change properly but the older version still stay in cache client browser loaded because the index.html version loading those files isn't the last (but those store in the cache browser)
I explain :
First build make an app.0000000.js (for exemple) and a runtime.0123456.js
The second make an app.000001.js and a runtime.654321.js
But the two first version still loading in broswer (due to the index.html file cached) so the client is stuck on a white page (because app.0000000.js still not exist it return an 404)
How can we force to clear the cache ?
In the index.html file of quasar we’ve adding this :
<meta http-equiv=“cache-control” content=“no-cache, no-store, private, must-revalidate, post-check=0, pre-check=0”>
<meta http-equiv=“cache-control” content=“max-age=0”>
<meta http-equiv=“expires” content=“0”>
<meta http-equiv=“expires” content=“Tue, 01 Jan 1980 1:00:00 GMT”>
<meta http-equiv=“pragma” content=“no-cache”>
We have an .htaccess too with :
<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType text/html M0
</IfModule>
<IfModule mod_headers.c>
<filesMatch "\.(html|htm|js|css)$">
FileETag None
Header unset ETag
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires 0
</filesMatch>
Header unset ETag
Header unset Last-Modified
</IfModule>
And in the httpd.conf file we have added this :
<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType text/html M0
</IfModule>
It's seems working properly on Safari and Firefox but on chrome we still have "Loaded from disk cache"
Chrome debug tool
More debug tool
Header properly set
This issue we're facing is a real problem, we will use service-worker in few weeks but we need a solution for clearing cache properly until we develop SW (no caching html will be better)
Thanks ! (And sorry for my english)
NB :
I've tried that : How to control web page caching, across all browsers?
And that : VueJS/browser caching production builds (similar problem)

how to override the cache control setting of httpd.conf from the page

We have the "cache-control" setting as "public" in httpd.conf
Header set Cache-Control "public"
But from the page we are trying to not cache it, hence we are setting the header as
<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
<cfheader name="Cache-Control" value="no-cache,no-store,must-revalidate">
But we found that, it always takes the cache-control setting from httpd.conf
Is there any way to override the header setting in httpd.conf from page level.
Note: "cfheader" is a ColdFusion tag to generates custom HTTP response headers to return to the client.

How to disable caching of a rewrite rule which proxies an internal server?

I'm using an htaccess rule to proxy to an internal server, using the answer recommended on this question, "Can ProxyPass and ProxyPassReverse Work in htaccess". I'm using htaccess as that is all I have access to. The method suggested works, but when I make a change on one of the internal pages and reload (from the external server) I don't even see it hitting the internal server, even after clearing the cache on the browser. In fact, if I try to load the page from another browser which never has tried to load the page before, it too gets the old copy.
This suggests something is being cached on the server, but how to change this? The apparent caching is rather annoying as I am trying to fix some issues that only occur on the proxied page.
If I hit the internal server directly and reload after a change, I always get the latest page.
I have tried a <filesMatch ...> rule for the affected pattern (using the same pattern as used in the RewriteRule in the following manner:
<filesMatch "^/?somedir/(.*)$">
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
</filesMatch>
My rewrite rule looks like this, and comes after the filesMatch directive:
RewriteEngine On
RewriteRule ^/?somedir/(.*)$ https://internal.local.net:8000/$1 [L,P]
But this has not had any effect. I have also tried "NoCache *" but this directive causes an error as it is not allowed in an .htaccess file.
The P-flag in your RewriteRule causes the request to be proxied to the internal server using mod_proxy. mod_proxy by itself does not cache content. The caching is probably a result of mod_cache being enabled as well on the server. The settings you need to disable caching for your internal server can unfortunately only be done in server or virtual-host config. The solution would be to add what you tried to the configuration of the internal server thus telling mod_cache that it should not cache any response from your internal server:
Using .htaccess
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
or PHP
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
header('Pragma: no-cache'); // HTTP 1.0.
header('Expires: 0'); // Proxies.
Try adding this in an htaccess file in your "somedir" directory:
ExpiresActive On
ExpiresDefault "now"

Why is this FilesMatch not matching correctly?

We have been attempting to configure our server not to cache our .htm files as it is causing a few issues with our analytics package as well as not displaying the pages correctly if the visitor hits the back button in their browser.
We have attempted to tackle it by adding:
<FilesMatch "\.(htm)$">
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
Header set Warning "Testing"
</FilesMatch>
to our httd file but it does not appear to execute, however, when we move the Header set outside of the FilesMatch it appears to execute fine..
Anyone have any ideas where we are going wrong?
I recently needed to figure out the same kind of problem and, although this post pointed me in the right direction, I wanted to share some clarifying information for the edification of those who search on this topic in the future.
David, your initial FilesMatch was not working because FilesMatch only works on real, physical files that exist on your filesystem. http://httpd.apache.org/docs/current/sections.html states it as:
The Directory and Files directives, along with their regex counterparts, apply directives to parts of the filesystem.
This is also why your second post using LocationMatch resolved the issue. Also from http://httpd.apache.org/docs/current/sections.html, it states:
The Location directive and its regex counterpart, on the other hand, change the configuration for content in the webspace. < SNIP > The directive need not have anything to do with the filesystem. For example, the following example shows how to map a particular URL to an internal Apache HTTP Server handler provided by mod_status. No file called server-status needs to exist in the filesystem.
<Location /server-status>
SetHandler server-status
</Location>
The Apache docs summarizes this behavior with the following statement:
Use Location to apply directives to content that lives outside the filesystem. For content that lives in the filesystem, use Directory and Files. An exception is < Location / >, which is an easy way to
apply a configuration to the entire server.
For those that want to understand more of the mechanics, this is how I understand the internals:
Location directives match based on the HTTP request URI (e.g. example.com/this/is/a/uri.htm without the example.com part).
Directory and Files directives, on the other hand, match based on whether there is a directory path or file in the filesystem of the DocumentRoot that matches to respective part of the the HTTP request URI
The Apache docs summarizes this behavior as:
What to use When
Choosing between filesystem containers and webspace containers is actually quite easy. When applying directives to objects that reside in the filesystem always use Directory or Files. When applying directives to objects that do not reside in the filesystem (such as a webpage generated from a database), use Location.
[IMPORTANT!] It is important to never use Location when trying to restrict access to objects in the filesystem. This is because many different webspace locations (URLs) could map to the same filesystem location, allowing your restrictions to be circumvented.
This issue has now been resolved.
In order to get it to work we have changed from using FilesMatch to LocationMatch and now the headers are being set perfectly.
We believe this is because the page is being redirected from a JSP page to an HTML page.
<LocationMatch "\.(htm|html)$">
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
Header set Warning "Testing"
</LocationMatch>
Hopefully others will find this helpful.

Redirect script.js to script.php

I have some javascript that is generated by PHP. Currently I am including the javeascript in the html using
<script type="text/javascript" src="js/script.php">
But I want to use
<script type="text/javascript" src="js/script.js">
Now script.js does not exist, but I want it to redirect to script.php without the user knowing.
Can this be done with .htaccess?
If your web server supports mod_rewrite, you could do something like this:
RewriteEngine On
RewriteRule ^js/script\.js$ js/script.php
If you have more than one script, you could generalize that RewriteRule by using a backreference from the test pattern:
RewriteRule ^js/(.*)\.js$ js/$1.php
In the parent directory you could have a .htaccess which maps all asset files to the relevant php file.
RewriteEngine on
RewriteRule ^js/(.*)\.js$ js/$1.js.php
RewriteRule ^css/(.*)\.css$ css/$1.css.php
notice I have kept the file extension for better readability.
Files
htdocs
mysite
assets
.htaccess
js->
script.js.php ( http://locahost/mysite/assets/js/script.js )
css->
style.css.php ( http://locahost/mysite/assets/css/style.js )
Headers
By default the files will be outputted as php, you will have to change the content type header to the correct type(js,css,txt,xml, etc).
You might also want to disable the files from being cached as they most probably change frequently.
You can either do this in all the php files or in the .htaccess file.
PHP
content type
js/*.js.php -> header("Content-type: text/javascript");
css/*.css.php ->header("Content-type: text/css");
cache
*.php -> header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
*.php -> header('Pragma: no-cache'); // HTTP 1.0.
*.php -> header('Expires: 0'); // Proxies.
.htaccess
content type
<FilesMatch \.js.php$>
Header set Cache-Control "no-transform"
Header set Content-Type "application/javascript; charset=utf-8"
</FilesMatch>
<FilesMatch \.css.php$>
Header set Cache-Control "no-transform"
Header set Content-Type "text/css; charset=utf-8"
</FilesMatch>
cache
<IfModule mod_headers.c>
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires 0
</IfModule>
If you just want your script src to end in ".js" you could always leave it as a .php file and link it in like this:
<script type="text/javascript" src="js/script.php?name=script.js">
This technique is commonly used with php or other scripts which generate images:
<img src="images/thumbnailer.php?x=foo.jpg">
This way if the browser tries to determine the type of file by the "extension," it will be "tricked" into using the right format.