J'ai un scénario dans Zuul où le service que l'URL est également routé pourrait être en panne. Ainsi, le corps de réponse reçoit 500 statuts HTTP et une exception ZuulException dans la réponse du corps JSON.
{
"timestamp": 1459973637928,
"status": 500,
"error": "Internal Server Error",
"exception": "com.netflix.zuul.exception.ZuulException",
"message": "Forwarding error"
}
Tout ce que je veux, c'est personnaliser ou supprimer la réponse JSON et peut-être changer le code d'état HTTP.
J'ai essayé de créer un gestionnaire d'exception avec @ControllerAdvice mais l'exception n'a pas été saisie par le gestionnaire.
MISES À JOUR:
J'ai donc étendu le filtre Zuul. Je peux le voir entrer dans la méthode d'exécution après que l'erreur a été exécutée. Comment puis-je modifier la réponse ensuite. Ci-dessous est ce que j'ai eu jusqu'à présent. J'ai lu quelque part à propos de SendErrorFilter mais comment puis-je implémenter cela et que fait-il?
public class CustomFilter extends ZuulFilter {
@Override
public String filterType() {
return "post";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
final RequestContext ctx = RequestContext.getCurrentContext();
final HttpServletResponse response = ctx.getResponse();
if (HttpStatus.INTERNAL_SERVER_ERROR.value() == ctx.getResponse().getStatus()) {
try {
response.sendError(404, "Error Error"); //trying to change the response will need to throw a JSON body.
} catch (final IOException e) {
e.printStackTrace();
} ;
}
return null;
}
Ajouté ceci à la classe qui a @EnableZuulProxy
@Bean
public CustomFilter customFilter() {
return new CustomFilter();
}
Nous avons finalement réussi à faire fonctionner ce travail [codé par un de mes collègues]: -
public class CustomErrorFilter extends ZuulFilter {
private static final Logger LOG = LoggerFactory.getLogger(CustomErrorFilter.class);
@Override
public String filterType() {
return "post";
}
@Override
public int filterOrder() {
return -1; // Needs to run before SendErrorFilter which has filterOrder == 0
}
@Override
public boolean shouldFilter() {
// only forward to errorPath if it hasn't been forwarded to already
return RequestContext.getCurrentContext().containsKey("error.status_code");
}
@Override
public Object run() {
try {
RequestContext ctx = RequestContext.getCurrentContext();
Object e = ctx.get("error.exception");
if (e != null && e instanceof ZuulException) {
ZuulException zuulException = (ZuulException)e;
LOG.error("Zuul failure detected: " + zuulException.getMessage(), zuulException);
// Remove error code to prevent further error handling in follow up filters
ctx.remove("error.status_code");
// Populate context with new response values
ctx.setResponseBody(“Overriding Zuul Exception Body”);
ctx.getResponse().setContentType("application/json");
ctx.setResponseStatusCode(500); //Can set any error code as excepted
}
}
catch (Exception ex) {
LOG.error("Exception filtering in custom error filter", ex);
ReflectionUtils.rethrowRuntimeException(ex);
}
return null;
}
}
J'ai eu le même problème et j'ai pu le résoudre plus simplement
Il suffit de mettre cela dans votre méthode Filter run()
if (<your condition>) {
ZuulException zuulException = new ZuulException("User message", statusCode, "Error Details message");
throw new ZuulRuntimeException(zuulException);
}
et SendErrorFilter
remettra à l'utilisateur le message avec la statusCode
souhaitée.
Cette exception dans un modèle d’exception ne s’apparente pas exactement à Nice, mais elle fonctionne ici.
Le transfert est souvent effectué par un filtre; dans ce cas, la demande n'atteint même pas le contrôleur. Cela expliquerait pourquoi votre @ControllerAdvice ne fonctionne pas.
Si vous transmettez dans le contrôleur, le @ControllerAdvice devrait fonctionner . Vérifiez si spring crée une instance de la classe annotée avec @ControllerAdvice. Pour cela, placez un point d'arrêt dans la classe et voyez s'il est touché.
Ajoutez également un point d'arrêt dans la méthode du contrôleur où le transfert devrait avoir lieu. Peut-être que vous invoquez accidentellement une autre méthode de contrôleur que vous inspectez?
Ces étapes devraient vous aider à résoudre le problème.
Dans votre classe annotée avec @ControllerAdvice, ajoutez une méthode ExceptionHandler annotée avec @ExceptionHandler (Exception.class), qui devrait intercepter toutes les exceptions.
EDIT: Vous pouvez essayer d'ajouter votre propre filtre qui convertit la réponse d'erreur renvoyée par le Zuulfilter. Là, vous pouvez changer la réponse à votre guise.
La manière dont la réponse d'erreur peut être personnalisée est expliquée ici:
traitement des exceptions pour le filtre au printemps
Placer le filtre correctement peut être un peu délicat. Vous ne savez pas exactement quelle est la position correcte, mais vous devez connaître l'ordre de vos filtres et l'emplacement où vous gérez l'exception.
Si vous le placez avant le Zuulfilter, vous devez coder le traitement de votre erreur après avoir appelé doFilter ().
Si vous le placez après le Zuulfilter, vous devez coder le traitement de votre erreur avant d'appeler doFilter ().
Ajouter des points d'arrêt dans votre filtre avant et après doFilter () peut aider à trouver la position correcte.
Voici les étapes à suivre avec @ControllerAdvice:
error
et laissez-le s’exécuter avant la SendErrorFilter
dans zuul même.RequestContext
pour empêcher l'exécution de SendErrorFilter
.RequestDispatcher
pour transmettre la demande à la ErrorController
- expliquée ci-dessous.AbstractErrorController
, puis relancez l'exception (ajoutez-la à l'étape de l'exécution de votre nouveau filtre d'erreur avec (clé, exception), récupérez-la à partir de la RequestContext
de votre contrôleur).L'exception sera maintenant interceptée dans votre classe @ControllerAdvice.
Zuul RequestContext ne contient pas le error.exception
mentionné dans cette réponse .
Mettre à jour le filtre d’erreur Zuul:
@Component
public class ErrorFilter extends ZuulFilter {
private static final Logger LOG = LoggerFactory.getLogger(ErrorFilter.class);
private static final String FILTER_TYPE = "error";
private static final String THROWABLE_KEY = "throwable";
private static final int FILTER_ORDER = -1;
@Override
public String filterType() {
return FILTER_TYPE;
}
@Override
public int filterOrder() {
return FILTER_ORDER;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
final RequestContext context = RequestContext.getCurrentContext();
final Object throwable = context.get(THROWABLE_KEY);
if (throwable instanceof ZuulException) {
final ZuulException zuulException = (ZuulException) throwable;
LOG.error("Zuul failure detected: " + zuulException.getMessage());
// remove error code to prevent further error handling in follow up filters
context.remove(THROWABLE_KEY);
// populate context with new response values
context.setResponseBody("Overriding Zuul Exception Body");
context.getResponse().setContentType("application/json");
// can set any error code as excepted
context.setResponseStatusCode(503);
}
return null;
}
}