3434from flask import request
3535from flask import Response
3636from flask import url_for
37+ from werkzeug .exceptions import HTTPException
3738from werkzeug .utils import import_string
3839
3940from .backends .base import BaseCache
@@ -369,6 +370,15 @@ def _call_fn(self, fn: Callable[..., Any], *args: Any, **kwargs: Any) -> Any:
369370 return ensure_sync (fn )(* args , ** kwargs )
370371 return fn (* args , ** kwargs )
371372
373+ def _call_fn_or_exception (
374+ self , fn : Callable [..., Any ], * args : Any , ** kwargs : Any
375+ ) -> Any :
376+ """Returns an ``HTTPException`` instead of propagating it."""
377+ try :
378+ return self ._call_fn (fn , * args , ** kwargs )
379+ except HTTPException as e :
380+ return e
381+
372382 @property
373383 def cache (self ) -> SimpleCache :
374384 """The backend instance the proxy methods delegate to. Use this to
@@ -572,6 +582,13 @@ def get_list():
572582 :param response_hit_indication: Default False.
573583 If True, it will add to response header field 'hit_cache'
574584 if used cache.
585+
586+ .. versionchanged:: 2.5.0
587+ A ``werkzeug.exceptions.HTTPException`` raised by the decorated
588+ function, for example through Flask's ``abort()``, is now cached
589+ like a returned response and re-raised on a cache hit. Use
590+ ``response_filter``, which is given the exception's response, to
591+ keep it out of the cache.
575592 """
576593
577594 def decorator (f : Callable [P , R ]) -> _CachedFunction [P , R ]:
@@ -642,12 +659,17 @@ def apply_caching(response: Response) -> Response:
642659 cache = self , cache_key = cache_key , args = args , kwargs = kwargs
643660 )
644661
662+ if found and isinstance (rv , HTTPException ):
663+ raise rv
664+
645665 if not found :
646- rv = self ._call_fn (f , * args , ** kwargs )
666+ rv = self ._call_fn_or_exception (f , * args , ** kwargs )
647667 if inspect .isgenerator (rv ):
648668 rv = join_generator (rv )
649669
650- if response_filter is None or response_filter (rv ):
670+ if response_filter is None or response_filter (
671+ rv .get_response () if isinstance (rv , HTTPException ) else rv
672+ ):
651673 cache_timeout = normalize_timeout (cached_fn .cache_timeout )
652674 if isinstance (rv , CachedResponse ):
653675 cache_timeout = rv .timeout or cache_timeout
@@ -662,6 +684,9 @@ def apply_caching(response: Response) -> Response:
662684 if self .app .debug :
663685 raise
664686 logger .exception ("Exception possibly due to cache backend." )
687+
688+ if isinstance (rv , HTTPException ):
689+ raise rv
665690 return rv
666691
667692 def default_make_cache_key (* args : Any , ** kwargs : Any ) -> str :
0 commit comments