How can I set the Cache-Control header for every response in Catalyst?
Asked Answered
H

2

6

It seems that by default Catalyst does not output Cache-Control:, etc. headers. I know I can output them in a given controller method like this:

$c->response->headers->last_modified(time);
$c->response->headers->expires(time + $self->{cache_time});
$c->response->headers->header(cache_control => "public, max-age=$self->{cache_time}");

It'd get pretty painful doing that in each method, though! What I'd prefer is:

  • A default set of headers (expires now, last modified now, cache-control: no-cache, pragma: no-cache)
  • A way to, per-method, override the default.

Is there a good way to accomplish this?

Hultgren answered 24/7, 2009 at 12:56 Comment(0)
O
6

derobert:

Excellent question. I covered exactly this in an article for the Catalyst advent calendar.

Basically you create a stash variable that defines your cache time for the given action, and then you process it in your Root end routine. See the article for all the details.

JayK

Obnoxious answered 24/7, 2009 at 17:11 Comment(4)
You may want to include a short snippet in this answer.Ropedancer
That wiki isn't loading for me at the moment (blank page or connection reset), but I can work with that idea. Thanks. And I can just default it to no-cache if one isn't set. Amazing this isn't built in to Catalyst; seems like every Catalyst app must have to do this!Hultgren
Ok, the wiki is back up. That's a really nice approach. That really ought to be part of Catalyst, or at least a plugin....Hultgren
People use Catalyst for a lot of different things and generally speaking we try to avoid adding things to Catalyst core when they aren't essential. The method is so simple that it's hardly worth creating a whole add-on for it. We usually just point folks in the direction of that wiki entry, as the whole addition is 12 lines not including comments. :-DObnoxious
G
4

Update: Based on your response to my earlier suggestion, I decided to bite the bullet and look at the Catalyst docs. It seems to me, the place to do this is in:

  sub end : Private {
    my ( $self, $c ) = @_;

    # handle errors etc.

    if ( $c->res->body ) {
        if ( "some condition" ) {
            set_default_response_headers( $c->response->headers );
            return;
        }
        else {
            do_something_else();
            return;
        }
    }
    $c->forward( 'MyApp::View::TT' ); # render template
}

Earlier response: I do not use Catalyst, but couldn't you just write a sub for your application?

sub set_default_response_headers {
    my ($h) = @_;
    $h->last_modified(time);
    $h->expires(time + $self->{cache_time});
    $h->header(cache_control => "public, max-age=$self->{cache_time}");
    return $h;    
}

Call with set_default_response_headers( $c->response->headers ).

Gully answered 24/7, 2009 at 13:24 Comment(1)
Yes, I could write a sub, but then I still have to remember to call it in every method... and if it gets forgotten in any controller method, it leads to a probable bug. Seems like a rather fragile approachHultgren

© 2022 - 2024 — McMap. All rights reserved.