SpringCloud学习系列之七 ----- Zuul路由网关的过滤器和异常处理 (2)

自定义的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

这里顺便说下禁用过滤器的规则。组件实现的过滤器,满足执行条件时都是会执行的,若我们想禁用某个过滤器时,可以在配置文件中配置。
规则:

zuul.<SimpleClassName>.<filterType>.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拿来进行使用既可。

测试

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfgdz.html