skip to Main Content

I’ve been trying to figure this one out for a few days now and have finally made a simplified enough test environment so that I can post this question with several examples.

The problem I’m running into is that my htaccess file is ignoring both the <If> and <Else> conditions. I am using Apache version 2.4.29 which does support this feature. Likewise, when I save the htaccess file, I do not get a 500-level error– the site works just fine (besides these being ignored).

My use case is that I’d like to listen for a query parameter and change the Cache-Control header based on whether that query parameter exists. I’m sure others would disagree with this premise and while I’m curious what a better solution would be, I would like to get to the bottom of this particular issue.

I’ve tried feeding several conditions to the <If> thinking that maybe it just didn’t like the format or that I was doing something wrong there, but I’ve now simplified it to be simply <If false> to try to force the <Else> side of the conditional. No matter what I do, neither side of the conditional is working– it is simply ignored completely.

Am I doing something wrong? I believe my syntax matches the documentation, but maybe I’m missing something… While I do have a lot of experience writing .htaccess files, I will admit I am far from an Apache expert.

Test cases

I made a webpage that simply loads a single image.png file and I read the Cache-Control header in Chrome DevTools.


Example A

.htaccess file contents:

<FilesMatch "png">
    Header set Cache-Control "max-age=123, public"
</FilesMatch>

<If false>
    <FilesMatch "png">
        Header unset Cache-Control
        Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    </FilesMatch>
</If>
<Else>
    <FilesMatch "png">
        Header set Cache-Control "max-age=31536000, public"
    </FilesMatch>
</Else>

Expected: The Cache-Control max-age should be 31536000

Actual: The Cache-Control max-age is 123

max-age is 123


Example B

.htaccess file contents:

<If false>
    <FilesMatch "png">
        Header unset Cache-Control
        Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    </FilesMatch>
</If>
<Else>
    <FilesMatch "png">
        Header set Cache-Control "max-age=31536000, public"
    </FilesMatch>
</Else>

Expected: The Cache-Control max-age should be 31536000

Actual: No Cache-Control header exists at all

No cache-control header at all


Edit: A clue has emerged that I am able to use 301 RedirectMatch inside the If/Else conditions, so it seems like the cache control headers are what is being ignored from within the conditionals… If that is the case, I’m curious what other options I have to make my use case (described above) work.

Edit 2: Another clue is that without the <FilesMatch> line, the Cache-Control max-age header is applied as expected (just not to the right files).

2

Answers


  1. Chosen as BEST ANSWER

    So I found a work-around for my specific use-case which is why I am "answering" my own question, but I am not "accepting" this answer as it does not resolve the core problem. I wanted to provide this for anyone who stumbles upon this issue in the future.

    What I found was that <FilesMatch> was what was being ignored inside of <If> and <Else> conditions. Redirects and headers could be set without a problem within them.

    So for my use-case, I flipped the logic around. I set the regular cache lengths as I wanted for individual file types using <FilesMatch> (outside of any conditionals). Then, I added an <If> condition to check for the query string, and if true it would unset all Cache-Control headers (so no FilesMatch as it was for all files).

    Here is an example of what I'm now doing for my work-around (in the same format as the above examples):

    # Set the cache headers as desired for individual files
    <FilesMatch "png">
        Header set Cache-Control "max-age=123, public"
    </FilesMatch>
    
    # When this condition is true unset all of the caches (to be replaced with a query string detection)
    <If true>
        # Notice no FilesMatch here– it affects all files
        Header unset Cache-Control
        Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    </If>
    

    Again, this does not actually answer the core question, so I am not going to "accept" my own answer, but I wanted to provide it for anyone else.


  2. You may be able to use if/else for .png files like this:

    <FilesMatch ".png$">
       <If false>
            Header unset Cache-Control
            Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
       </If>
       <Else>
            Header set Cache-Control "max-age=31536000, public"
       </Else>
    </FilesMatch>
    

    Expectedly it will set Cache-Control: max-age=31536000, public for all .png files.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search