Conditionally sending a Cache-Control header?

I want a long expiring Cache-Control header for JavaScript files. I am not sure if I’ve misconfigured something, or how to figure out only setting this header on files that are found. It seems like I can’t control setting the header only if the file exists, and I am hoping someone can help me figure it out?

When I make a request to a file that doesn’t exist, I still get the “Cache-Control” and “Expires” headers back. Actually I think “Expires” was redundant in modern browsers:

curl -I https://example.com/js/foo.js
HTTP/1.1 404 Not Found
Date: Fri, 04 Aug 2017 22:45:55 GMT
Content-Type: text/plain; charset=utf-8
Connection: keep-alive
Cache-Control: public, max-age=31536000
Expires: Sat, 04 Aug 2018 21:57:35 GMT
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
CF-Cache-Status: HIT
Server: cloudflare-nginx
CF-RAY: 38950cbe2e3139b2-PHX

Here is my Caddyfile (I am running this in Docker and terminating SSL):

0.0.0.0
root /srv/app/public
browse
gzip

fastcgi / 127.0.0.1:9000 php
rewrite {
    if {path} not_starts_with /api/v1
    if {path} not_starts_with /api/latest
    ext /
    to /index.php?{query}
}

proxy /api/latest {$API_BASE_URL} {
    transparent
}

proxy /api/v1 {$API_BASE_URL} {
    transparent
}

expires {
    match .css|.js$ 1y
}

# Remove the `Server: Caddy` header
header / -Server

# Long JavaScript expiry (1 year)
header /js {
  Cache-Control "public, max-age=31536000"
}

# Long CSS expiry (1 year)
header /css {
  Cache-Control "public, max-age=31536000"
}

log stdout
errors stdout
startup php-fpm &

I think this part is your issue:

# Long JavaScript expiry (1 year)
header /js {
  Cache-Control "public, max-age=31536000"
}

# Long CSS expiry (1 year)
header /css {
  Cache-Control "public, max-age=31536000"
}

Those header entries don’t care whether or not Caddy actually returned a file, it will just set that header for any requests matching /css or /js.

Try without them - I think your expires directive should handle .js and .css files already (although that regex looks strange to me without round braces around the grouping).

Thanks for the info, how can I only conditionally set the Cache-Control headers when a file exists? Browsers will use Cache-Control, I am setting the Expires only in case a proxy uses it for some reason.

Also, you mentioned the regex looks strange, how would you recommend I format the regex differently?

Thank you kindly!

I don’t believe you can currently configure Caddy to validate the existance of a file before setting headers in this manner. If it’s a problem, I’d suggest going to the issues page of the Github repo and submitting a feature request.

As for the regex, I’m used to seeing match groups written in round brackets, like: (.css|.js)$

Would you mind showing me a more complete examle using (.css|.js)$, like this?

header (.css|.js)$ {
  Cache-Control "public, max-age=31536000"
}

You’ve got it exactly.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.