自定义的Filter代码:
@Component public class MyZuulFilter extends ZuulFilter{ @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); ctx.addZuulResponseHeader("Content-type", "text/json;charset=UTF-8"); ctx.getResponse().setCharacterEncoding("UTF-8"); System.out.println("请求地址:"+request.getRequestURI()); String token = request.getParameter("token"); String msg="请求成功!"; if(token==null) { ctx.setSendZuulResponse(false); msg="请求失败!"; ctx.setResponseBody(msg); ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); } return msg; } @Override public String filterType() { return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { return 0; } @Bean public MyZuulFilter zuulFilter() { return new MyZuulFilter(); } } 自定义异常类处理Zuul除了可以自定义过滤器之外,也可以对异常结果进行处理,以保持返回值一致。在进行Zuul使用的时候发现了在发生了异常之后,会调用SendErrorFilter异常过滤器,对异常经常处理,同时重定向至/error这个路径中。所以如果我们需要自定义对异常处理的话,继承SendErrorFilter该类就可以实现了。我们查看SendErrorFilter源码,其实也是继承ZuulFilter该类并实现里面的一些方法,做的自定义异常封装,其实也可以把SendErrorFilter该类当做一个自定义的过滤器。
由于SendErrorFilter是对ZuulFilter类进行了二次封装,所以我们自定义的Error代码只需继承SendErrorFilter改成,然后实现其中的run方法即可。
自定义的Error代码:
@Component public class MyErrorFilter extends SendErrorFilter{ @Override public Object run() { String msg="请求失败!"; try{ RequestContext ctx = RequestContext.getCurrentContext(); ExceptionHolder exception = findZuulException(ctx.getThrowable()); System.out.println("错误信息:"+exception.getErrorCause()); msg+="error:"+exception.getErrorCause(); HttpServletResponse response = ctx.getResponse(); response.setCharacterEncoding("UTF-8"); response.getOutputStream().write(msg.getBytes()); }catch (Exception ex) { ex.printStackTrace(); ReflectionUtils.rethrowRuntimeException(ex); } return msg; } @Bean public MyErrorFilter errorFilter() { return new MyErrorFilter(); } }这里我们还需要禁用SendErrorFilter过滤器,不然是不会使用我们自定的异常过滤器的。
在application.properties 添加如下配置:
zuul.SendErrorFilter.error.disable=true这里顺便说下禁用过滤器的规则。组件实现的过滤器,满足执行条件时都是会执行的,若我们想禁用某个过滤器时,可以在配置文件中配置。
规则:
说明:
SimpleClassName为类名,filterType过滤器类型
当然,如果觉得上述的异常处理还是不够优雅的话,可以使用ControllerAdvice注解进行全局异常处理,该注解的使用示例可以从个人的springboot项目中进行找到,地址:https://github.com/xuwujing/springBoot-study
自定义异常回退处理在之前的关于springcloud中SpringCloud学习系列之三----- 断路器(Hystrix)和断路器监控(Dashboard)这篇文章中讲解过服务的降级处理,其实这里的处理也是类似,也就是某个服务无法进行访问的时候,进行回退处理。
这里我们自定义异常回退处理的代码相对而已也比较简单,只需实现FallbackProvider该接口的方法既可。
该类的源码如下:
getRoute该方法主要是指定需要回退服务的名称。
fallbackResponse该方法提供基于执行失败原因并进行回退响应。
了解之后该源码之后,我们再来编写一个自定义异常回退处理的类。
自定义的Fallback代码:
@Component public class MyFallback implements FallbackProvider { private static final String SERVER_NAME="springcloud-zuul-filter-server2"; @Override public String getRoute() { return SERVER_NAME; } @Override public ClientHttpResponse fallbackResponse(String route, Throwable cause) { //标记不同的异常为不同的http状态值 if (cause instanceof HystrixTimeoutException) { return response(HttpStatus.GATEWAY_TIMEOUT); } else { //可继续添加自定义异常类 return response(HttpStatus.INTERNAL_SERVER_ERROR); } } //处理 private ClientHttpResponse response(final HttpStatus status) { String msg="该"+SERVER_NAME+"服务暂时不可用!"; return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return status; } @Override public int getRawStatusCode() throws IOException { return status.value(); } @Override public String getStatusText() throws IOException { return status.getReasonPhrase(); } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream(msg.getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } @Bean public MyFallback eurekaClientFallback() { return new MyFallback(); } } 客户端客户端这边,我们可以把之前springcloud-zuul项目中的springcloud-zuul-server1和springcloud-zuul-server2拿来进行使用既可。
测试