Il est également possible de filtrer une réponse à l'aide d'un filtre. Le déroulement des opérations
est un peu plus délicat, car on doit dans ce cas fournir une réponse qui n'est pas la vraie réponse
à la méthode doFilter()
.
Effectivement, fournir à cette méthode la vraie réponse pourrait donner la possibilité aux filtres
suivants ou à la servlet finale, d'écrire directement dans le buffer de réponse, et de faire appel
à sa méthode flush()
, ce qui enverrait directement la réponse au navigateur client.
On ne pourrait donc plus agir sur le contenu de la réponse.
L'idée consiste donc à fournir à la chaîne un buffer que l'on construit nous-mêmes, et dont on peut
contrôler l'écriture dans le vrai buffer de réponse. Comme l'objet réponse que l'on doit passer en
paramètre de doFilter()
est de type ServletResponse
, il nous faut construire
une implémentation de cette classe.
Il ne s'agit bien sûr pas de réécrire l'intégralité de cette classe, juste d'intercepter ce que
la servlet pourrait écrire dans le buffer de réponse. Pour cela, on peut surcharger la méthode
getWriter()
de façon à retourner un PrintWriter
sur notre buffer,
plutôt que sur le buffer de réponse.
Écrivons tout d'abord notre implémentation de ServletResponse
.
Exemple 4.5. Filtrage avec modification de la réponse - 1
public class CustomServletResponse extends HttpServletResponseWrapper { // création d'un writer sur un buffer en mémoire private Writer writer = new CharArrayWriter() ; public CustomServletResponse(HttpServletResponseWrapper response) { super(response) ; } @Override public PrintWriter getWriter() { // retourne un PrintWriter sur notre buffer plutôt que sur // la vraie réponse return new PrintWriter(writer) ; } public String toString() { return writer.toString() ; } }
Utilisons ensuite cette implémentation en filtrage.
Exemple 4.6. Filtrage avec modification de la réponse - 2
public class PostFilter implements Filter { // méthodes init() et destroy() public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { // construction de notre fausse réponse ServletResponse fakeResponse = new CustomServletResponse(response) ; // appel de la servlet filterChain.doFilter(request, response) ; // récupération de la réponse qu'elle a généré String providedResponse = fakeResponse.toString() ; // on peut modifier cette réponse ici String modifiedResponse = ... ; // puis l'envoyer vers le client // on remet les en-têtes HTTP en fonction de ce qui a été fait response.setContentLength(modifiedResponse.length()) ; // envoi de la réponse modifiée sur le flux de sortie PrintWriter printWriter = response.getWriter() ; printWriter.write(modifiedResponse) ; printWriter.close() ; } }
Cet exemple reste assez basique. Si les méthodes qui interrogent la réponse vont fonctionner
correctement, notre implémentation risque fort d'échouer si la servlet filtrée fait un appel
à la méthode
getOutputStream()
, ou aux méthodes setContentType()
,
setCharacterEncoding()
, ou encore sendError()
. Il convient
donc de le compléter avant de le mettre en production, ou de ne l'utiliser que dans des
cas simples et parfaitement maîtrisés.