-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #48 from hiit-consulting-fr/feat/cache-control
feat(cache): add cache control annotation
- Loading branch information
Showing
8 changed files
with
277 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
src/main/java/fr/hiitconsulting/socle/application/annotation/CacheControl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* MIT License | ||
* | ||
* Copyright (c) 2024 Hi!T Consulting | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in all | ||
* copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
* | ||
*/ | ||
|
||
package fr.hiitconsulting.socle.application.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Annotation permettant de gérer le header Cache-Control | ||
* | ||
* <br><br> | ||
* L'en-tête HTTP Cache-Control contient des directives (c'est-à-dire des instructions), | ||
* dans les requêtes et dans les réponses, pour contrôler la mise en cache dans les navigateurs | ||
* et caches partagées (par exemple les proxies, CDN). | ||
*/ | ||
@Target(ElementType.METHOD) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface CacheControl { | ||
|
||
/** | ||
* La directive de réponse max-age=N indique que la réponse reste fraîche jusqu'à N secondes après la génération de la réponse. | ||
* <br><br> | ||
* Cela indique que les caches peuvent stocker cette réponse et la réutiliser pour les requêtes suivantes tant qu'elle est fraîche. | ||
* <br><br> | ||
* On notera que max-age ne correspond pas au temps écoulé depuis que la réponse a été reçue, | ||
* il s'agit du temps écoulé depuis que la réponse a été générée sur le serveur d'origine. | ||
* Ainsi, si les autres caches situés sur la route réseau empruntée par la réponse stockent la réponse | ||
* pendant 100 secondes (en l'indiquant avec l'en-tête de réponse Age), le cache du navigateur déduira | ||
* 100 secondes de la durée de fraîcheur. | ||
*/ | ||
long maxAge() default 30; | ||
|
||
/** | ||
* La directive de réponse no-cache indique que la réponse peut être stockée en cache, mais qu'elle doit être validée | ||
* avec le serveur d'origine avant chaque réutilisation, même si le cache est déconnecté du serveur d'origine. | ||
* <br><br> | ||
* Si vous souhaitez que les caches vérifient leur contenu à chaque mise à jour tout en réutilisant du contenu stocké, | ||
* no-cache est la directive à utiliser. | ||
* <br><br> | ||
* On notera que no-cache ne signifie pas « ne pas mettre en cache ». | ||
* no-cache permet aux caches de stocker une réponse, mais impose une revalidation avant toute réutilisation. | ||
* Si vous souhaitez effectivement ne pas stocker de données pour ne pas avoir de cache du tout, | ||
* il faudra utiliser la directive no-store. | ||
*/ | ||
boolean noCache() default false; | ||
|
||
/** | ||
* La directive de réponse no-store indique qu'aucun cache (partagé ou privé) ne doit stocker la réponse. | ||
*/ | ||
boolean noStore() default false; | ||
|
||
/** | ||
* La directive de réponse stale-while-revalidate indique que le cache peut réutiliser | ||
* une réponse périmée pendant qu'il la revalide dans un cache. | ||
* <br><br> | ||
* ex: | ||
* <code>Cache-Control: max-age=604800, stale-while-revalidate=86400</code> | ||
* <br><br> | ||
* Dans l'exemple qui précède, la réponse est fraîche pendant 7 jours (604800s). | ||
* Après 7 jours, elle devient périmée, mais le cache peut être réutilisé pour les requêtes | ||
* qui sont faites le jour suivant (86400s), tant que la revalidation de la réponse a lieu en arrière-plan. | ||
* <br><br> | ||
* La revalidation rafraîchira le cache à nouveau et la réponse apparaîtra donc comme toujours fraîche | ||
* aux clients pendant cette période, masquant ainsi la latence induite par une revalidation. | ||
* <br><br> | ||
* Si aucune requête n'a lieu pendant cette période intermédiaire, | ||
* le cache devient périmé et la prochaine requête revalidera le cache normalement. | ||
*/ | ||
long staleWhileRevalidate() default 30; | ||
|
||
/** | ||
* La directive de réponse private indique que la réponse peut uniquement être enregistrée dans un cache privé | ||
* (c'est-à-dire le cache local des navigateurs). | ||
* <br><br> | ||
* Si private est oubliée pour une réponse avec du contenu personnalisé, cette réponse pourra être enregistrée | ||
* dans un cache partagé et finir par être réutilisée pour plusieurs personnes, | ||
* causant ainsi une fuite d'informations personnelles. | ||
*/ | ||
boolean privateCache() default true; | ||
|
||
} |
87 changes: 87 additions & 0 deletions
87
src/main/java/fr/hiitconsulting/socle/application/cache/CacheAnnotationInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* MIT License | ||
* | ||
* Copyright (c) 2024 Hi!T Consulting | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in all | ||
* copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
* | ||
*/ | ||
|
||
package fr.hiitconsulting.socle.application.cache; | ||
|
||
import fr.hiitconsulting.socle.application.annotation.CacheControl; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import org.springframework.web.method.HandlerMethod; | ||
import org.springframework.web.servlet.HandlerInterceptor; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import static org.springframework.http.HttpHeaders.CACHE_CONTROL; | ||
|
||
public class CacheAnnotationInterceptor implements HandlerInterceptor { | ||
|
||
|
||
@Override | ||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { | ||
|
||
if (handler instanceof HandlerMethod hm) { | ||
|
||
handleCacheControlAnnotation(response, hm.getMethodAnnotation(CacheControl.class)); | ||
|
||
} | ||
|
||
return true; | ||
} | ||
|
||
private void handleCacheControlAnnotation(HttpServletResponse response, CacheControl annotation) { | ||
if (annotation == null) { | ||
return; | ||
} | ||
|
||
List<String> headerValues = new ArrayList<>(); | ||
if (annotation.noCache()) { | ||
headerValues.add("no-cache"); | ||
|
||
if (annotation.noStore()) { | ||
headerValues.add("no-store"); | ||
} | ||
} else { | ||
if (annotation.privateCache()) { | ||
headerValues.add("private"); | ||
} | ||
|
||
if (annotation.maxAge() > 0) { | ||
headerValues.add("max-age=" + annotation.maxAge()); | ||
} | ||
|
||
if (annotation.staleWhileRevalidate() > 0) { | ||
headerValues.add("stale-while-revalidate=" + annotation.staleWhileRevalidate()); | ||
} | ||
} | ||
|
||
response.setHeader(CACHE_CONTROL, String.join(", ", headerValues)); | ||
} | ||
|
||
} | ||
|
||
|
||
|
||
|
50 changes: 50 additions & 0 deletions
50
src/main/java/fr/hiitconsulting/socle/application/configuration/CacheConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* MIT License | ||
* | ||
* Copyright (c) 2024 Hi!T Consulting | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in all | ||
* copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
* | ||
*/ | ||
|
||
package fr.hiitconsulting.socle.application.configuration; | ||
|
||
import fr.hiitconsulting.socle.application.cache.CacheAnnotationInterceptor; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.web.filter.ShallowEtagHeaderFilter; | ||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
|
||
@Configuration | ||
@RequiredArgsConstructor | ||
public class CacheConfiguration implements WebMvcConfigurer { | ||
|
||
@Override | ||
public void addInterceptors(InterceptorRegistry registry) { | ||
registry.addInterceptor(new CacheAnnotationInterceptor()); | ||
} | ||
|
||
@Bean | ||
public ShallowEtagHeaderFilter shallowEtagHeaderFilter() { | ||
return new ShallowEtagHeaderFilter(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 27 additions & 1 deletion
28
...esources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,27 @@ | ||
fr.hiitconsulting.socle.infrastructure.configuration.RequestLoggingFilterConfig | ||
# | ||
# MIT License | ||
# | ||
# Copyright (c) 2024 Hi!T Consulting | ||
# | ||
# Permission is hereby granted, free of charge, to any person obtaining a copy | ||
# of this software and associated documentation files (the "Software"), to deal | ||
# in the Software without restriction, including without limitation the rights | ||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
# copies of the Software, and to permit persons to whom the Software is | ||
# furnished to do so, subject to the following conditions: | ||
# | ||
# The above copyright notice and this permission notice shall be included in all | ||
# copies or substantial portions of the Software. | ||
# | ||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
# SOFTWARE. | ||
# | ||
# | ||
|
||
fr.hiitconsulting.socle.application.configuration.RequestLoggingFilterConfig | ||
fr.hiitconsulting.socle.application.configuration.CacheConfiguration |