We are using ExpressionEngine as a CMS. It allows you to set the "type" of the file when you create a template and when naming it, you don't have to give it an extension.

I have used this to set cache-control but it doesn't work on many of my javascript and css files because they don't have .css and .js extensions. Is there a way to make it work on type?

<IfModule mod_expires.c>
    # Enable expirations
    ExpiresActive On 
    # Default directive
    ExpiresDefault "access plus 1 month"
    # My favicon
    ExpiresByType image/x-icon "access plus 1 year"
    # Images
    ExpiresByType image/gif "access plus 6 months"
    ExpiresByType image/png "access plus 6 months"
    ExpiresByType image/jpg "access plus 6 months"
    ExpiresByType image/jpeg "access plus 6 months"
    # CSS
    ExpiresByType text/css "access plus 4 months"
    # Javascript
    ExpiresByType application/javascript "access plus 6 months"
<IfModule mod_deflate.c>
    # Force compression for mangled headers.
    # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping
    <IfModule mod_setenvif.c>
        <IfModule mod_headers.c>
            SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
            RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding

    # Compress all output labeled with one of the following MIME-types
    # (for Apache versions below 2.3.7, you don't need to enable `mod_filter`
    #  and can remove the `<IfModule mod_filter.c>` and `</IfModule>` lines
    #  as `AddOutputFilterByType` is still in the core directives).

    <IfModule mod_filter.c>
        AddOutputFilterByType DEFLATE application/atom+xml \
        application/javascript \
        application/json \
        application/rss+xml \
        application/vnd.ms-fontobject \
        application/x-font-ttf \
        application/x-web-app-manifest+json \
        application/xhtml+xml \
        application/xml \
        font/opentype \
        image/svg+xml \
        image/x-icon \
        text/css \
        text/html \
        text/javascript \
        text/plain \
        text/x-js \
        text/x-component \

# configure mod_headers
# URL: http://httpd.apache.org/docs/2.2/mod/mod_headers.html
<IfModule mod_headers.c>
    <FilesMatch "\\.(ico|jpe?g|png|gif|swf|css|js)$">
        Header set Cache-Control "max-age=2692000, public"
    <FilesMatch "\\.(x?html?|php)$">
        Header set Cache-Control "max-age=600, private, must-revalidate"
    Header unset ETag
    Header unset Last-Modified

By "type" I assume you mean mime-type, in which case you should look at mod_expires and the ExpiresByType directive - this is undoubtedly the easiest/modern way to set the appropriate Expires and Cache-Control (max-age directive) HTTP response headers.

It goes something like:

ExpiresActive On
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType text/css "access plus 1 month"

This is using the "alternative syntax". Ensure that the mime-types stated match the mime-types that your server is responding with. (2692000 seconds would seem to be close to 1 month)

However, if you need to modify other directives of the Cache-Control header then you will still need to use the Header directive.

<FilesMatch "\\.(ico|jpe?g|png|gif|swf|css|js)$">

Aside: the double backslash at the start of the regex is superfluous, you only need to escape the literal dot. ie. "\.(ico| etc.


I already have the ExpiresByType info set.

The Header directive (mod_headers) will take priority if the corresponding FilesMatch container matches. However, you say that many of these files "don't have .css and .js extensions", so it's not going to match and the ExpiresByType directives are going to take priority in these instances.

You do have a conflict of interests between your mod_expires and mod_headers directives. With mod_expires (ExpiresByType) you are trying to cache CSS and JS files for 4 and 6 months respectively, with mod_headers (Header) you state a cache time of 1 month for both?! So, without a file extension present, these files are going to be cached for 4 and 6 months, regardless of your Header directive.

Also, you should note that the ExpiresByType directive also sets the Expires HTTP response header (for old browsers). This is going to conflict with the Cache-Control header that you are manually setting with the Header directive. Although all modern browsers should prioritise Cache-Control over Expires.

Basically, you don't need to use Header set Cache-Control ... if you are using mod_expires. Or, if you do, you need to make sure they are both doing the same thing.

  • I already have the ExpiresByType info set. Does the Cache-Control override that or vice-versa? I do need to set the max-age attribute. – MB34 Sep 6 '16 at 22:32
  • Both the ExpiresByType and Headers directives in the (updated) code in your question set the max-age attribute of the Cache-Control header. This is a conflict. I've updated my answer. – MrWhite Sep 7 '16 at 0:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.