zoukankan      html  css  js  c++  java
  • zuul网关Filter处理流程及异常处理

    本文转载自:https://blog.csdn.net/tianyaleixiaowu/article/details/77893822

    上一篇介绍了java网关Zuul的简单使用,进行请求路由转发和过滤器的基本操作。

    这一篇主要看一下它的过滤器Filter的工作流程及异常处理。

    首先看到Filter的四个方法,FilterType,filterOrder,shouldFilter,run。

    filterType代表过滤类型

    PRE: 该类型的filters在Request routing到源web-service之前执行。用来实现Authentication、选择源服务地址等
    ROUTING:该类型的filters用于把Request routing到源web-service,源web-service是实现业务逻辑的服务。这里使用HttpClient请求web-service。
    POST:该类型的filters在ROUTING返回Response后执行。用来实现对Response结果进行修改,收集统计数据以及把Response传输会客户端。
    ERROR:上面三个过程中任何一个出现错误都交由ERROR类型的filters进行处理。
    主要关注 pre、post和error。分别代表前置过滤,后置过滤和异常过滤。
    如果你的filter是pre的,像上一篇那种,就是指请求先进入pre的filter类,你可以进行一些权限认证,日志记录,或者额外给Request增加一些属性供后续的filter使用。pre会优先按照order从小到大执行,然后再去执行请求转发到业务服务。
    再说post,如果type为post,那么就会执行完被路由的业务服务后,再进入post的filter,在post的filter里,一般做一些日志记录,或者额外增加response属性什么的。
    最后error,如果在上面的任何一个地方出现了异常,就会进入到type为error的filter中。

    filterOrder代表过滤器顺序

    这个不多说,试一下就知道了。

    shouldFilter代表这个过滤器是否生效

    true代表生效,false代表不生效。那么什么情况下使用不生效呢,不生效干嘛还要写这个filter类呢?
    其实是有用的,有时我们会动态的决定让不让一个filter生效,譬如我们可能根据Request里是否携带某个参数来判断是否需要生效,或者我们需要从上一个filter里接收某个数据来决定,再或者我们希望能手工控制是否生效(使用如Appolo之类的配置中心,来动态设置该字段)。

    Run方法

    这个是主要的处理逻辑的地方,我们做权限控制、日志等都是在这里。
     
    下图是filter的执行顺序。
    直接用一个简单的示例来看看结果
    第一个前置过滤器
    package com.tianyalei.testzuul;  
      
    import com.netflix.zuul.ZuulFilter;  
    import com.netflix.zuul.context.RequestContext;  
    import org.slf4j.Logger;  
    import org.slf4j.LoggerFactory;  
    import org.springframework.stereotype.Component;  
      
    import javax.servlet.http.HttpServletRequest;  
      
    @Component  
    public class AccessFilter extends ZuulFilter {  
      
        private static Logger log = LoggerFactory.getLogger(AccessFilter.class);  
      
        @Override  
        public String filterType() {  
            //前置过滤器  
            return "pre";  
        }  
      
        @Override  
        public int filterOrder() {  
            //优先级,数字越大,优先级越低  
            return 0;  
        }  
      
        @Override  
        public boolean shouldFilter() {  
            //是否执行该过滤器,true代表需要过滤  
            return true;  
        }  
      
        @Override  
        public Object run() {  
            RequestContext ctx = RequestContext.getCurrentContext();  
            HttpServletRequest request = ctx.getRequest();  
      
            log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString());  
      
            //获取传来的参数accessToken  
            Object accessToken = request.getParameter("accessToken");  
            if(accessToken == null) {  
                log.warn("access token is empty");  
                //过滤该请求,不往下级服务去转发请求,到此结束  
                ctx.setSendZuulResponse(false);  
                ctx.setResponseStatusCode(401);  
                ctx.setResponseBody("{"result":"accessToken为空!"}");  
                ctx.getResponse().setContentType("text/html;charset=UTF-8");  
                return null;  
            }  
            //如果有token,则进行路由转发  
            log.info("access token ok");  
            //这里return的值没有意义,zuul框架没有使用该返回值  
            return null;  
        }  
      
    }  

    第二个前置过滤器

    package com.tianyalei.testzuul;  
      
    import com.netflix.zuul.ZuulFilter;  
    import com.netflix.zuul.context.RequestContext;  
    import org.slf4j.Logger;  
    import org.slf4j.LoggerFactory;  
    import org.springframework.stereotype.Component;  
      
    import javax.servlet.http.HttpServletRequest;  
      
    @Component  
    public class SecondFilter extends ZuulFilter {  
      
        private static Logger log = LoggerFactory.getLogger(SecondFilter.class);  
      
        @Override  
        public String filterType() {  
            //前置过滤器  
            return "pre";  
        }  
      
        @Override  
        public int filterOrder() {  
            //优先级,数字越大,优先级越低  
            return 1;  
        }  
      
        @Override  
        public boolean shouldFilter() {  
            //是否执行该过滤器,true代表需要过滤  
            return true;  
        }  
      
        @Override  
        public Object run() {  
            RequestContext ctx = RequestContext.getCurrentContext();  
            HttpServletRequest request = ctx.getRequest();  
      
            log.info("second过滤器");  
      
            return null;  
      
        }  
      
    }

    后置过滤器

    package com.tianyalei.testzuul;  
      
    import com.netflix.zuul.ZuulFilter;  
    import com.netflix.zuul.context.RequestContext;  
    import org.slf4j.Logger;  
    import org.slf4j.LoggerFactory;  
    import org.springframework.stereotype.Component;  
      
    @Component  
    public class PostFilter extends ZuulFilter {  
      
        private static Logger log = LoggerFactory.getLogger(PostFilter.class);  
      
        @Override  
        public String filterType() {  
            //后置过滤器  
            return "post";  
        }  
      
        @Override  
        public int filterOrder() {  
            //优先级,数字越大,优先级越低  
            return 0;  
        }  
      
        @Override  
        public boolean shouldFilter() {  
            //是否执行该过滤器,true代表需要过滤  
            return true;  
        }  
      
        @Override  
        public Object run() {  
            RequestContext ctx = RequestContext.getCurrentContext();  
            log.info("进入post过滤器");  
            System.out.println(ctx.getResponseBody());  
      
            ctx.setResponseBody("post后置数据");  
      
            int i = 1 / 0;  
      
            return null;  
      
        }  
      
    }

    异常过滤器

    package com.tianyalei.testzuul;  
      
    import com.netflix.zuul.ZuulFilter;  
    import com.netflix.zuul.context.RequestContext;  
    import org.slf4j.Logger;  
    import org.slf4j.LoggerFactory;  
    import org.springframework.stereotype.Component;  
      
    @Component  
    public class ErrorFilter extends ZuulFilter {  
      
        private static Logger log = LoggerFactory.getLogger(ErrorFilter.class);  
      
        @Override  
        public String filterType() {  
            //异常过滤器  
            return "error";  
        }  
      
        @Override  
        public int filterOrder() {  
            //优先级,数字越大,优先级越低  
            return 0;  
        }  
      
        @Override  
        public boolean shouldFilter() {  
            //是否执行该过滤器,true代表需要过滤  
            return true;  
        }  
      
        @Override  
        public Object run() {  
            RequestContext ctx = RequestContext.getCurrentContext();  
      
            log.info("进入异常过滤器");  
      
            System.out.println(ctx.getResponseBody());  
      
            ctx.setResponseBody("出现异常");  
      
            return null;  
      
        }  
      
    }

    定义好之后,直接测试看看

    可以看到结果就是按照上面说的顺序在执行。
    但是最终给用户呈现这样一个界面就不合适的,我们应该去处理这个"/error"映射的问题。
    所以我再定义一个Controller
    package com.tianyalei.testzuul;  
      
    import org.springframework.boot.autoconfigure.web.ErrorController;  
    import org.springframework.web.bind.annotation.RequestMapping;  
    @RestController  
    public class ErrorHandlerController implements ErrorController {  
      
        /** 
         * 出异常后进入该方法,交由下面的方法处理 
         */  
        @Override  
        public String getErrorPath() {  
            return "/error";  
        }  
      
        @RequestMapping("/error")  
        public String error() {  
            return "出现异常";  
        }  
    }  

    在"/error"方法里返回你想给客户端返回的值即可。

  • 相关阅读:
    【LeetCode】17. Letter Combinations of a Phone Number
    【LeetCode】16. 3Sum Closest
    【LeetCode】15. 3Sum 三个数和为0
    【LeetCode】14. Longest Common Prefix 最长前缀子串
    【LeetCode】13. Roman to Integer 罗马数字转整数
    【LeetCode】12. Integer to Roman 整型数转罗马数
    【LeetCode】11. Container With Most Water
    【LeetCode】10. Regular Expression Matching
    Models of good programmer
    RSA Algorithm
  • 原文地址:https://www.cnblogs.com/wpcnblog/p/9054837.html
Copyright © 2011-2022 走看看