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"方法里返回你想给客户端返回的值即可。

原文地址:https://www.cnblogs.com/wpcnblog/p/9054837.html

时间: 2024-08-30 16:42:57

zuul网关Filter处理流程及异常处理的相关文章

spring cloud深入学习(十二)-----Spring Cloud Zuul网关 Filter、熔断、重试、高可用的使用方式

Zuul的核心 Filter是Zuul的核心,用来实现对外服务的控制.Filter的生命周期有4个,分别是“PRE”.“ROUTING”.“POST”.“ERROR”,整个生命周期可以用下图来表示. Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期. PRE: 这种过滤器在请求被路由之前调用.我们可利用这种过滤器实现身份验证.在集群中选择请求的微服务.记录调试信息等. ROUTING:这种过滤器将请求路由到微服务.这种过滤器用于构建发送给微服务的请求,并使用Apa

最全面的改造Zuul网关为Spring Cloud Gateway(包含Zuul核心实现和Spring Cloud Gateway核心实现)

前言: 最近开发了Zuul网关的实现和Spring Cloud Gateway实现,对比Spring Cloud Gateway发现后者性能好支持场景也丰富.在高并发或者复杂的分布式下,后者限流和自定义拦截也很棒. 提示: 本文主要列出本人开发的Zuul网关核心代码以及Spring Cloud Gateway核心代码实现.因为本人技术有限,主要是参照了 Spring Cloud Gateway 如有不足之处还请见谅并留言指出. 1:为什么要做网关 (1)网关层对外部和内部进行了隔离,保障了后台服

springcloud学习之路: (三) springcloud集成Zuul网关

网关就是做一下过滤或拦截操作 让我们的服务更加安全 用户访问我们服务的时候就要先通过网关 然后再由网关转发到我们的微服务 1. 新建一个网关服务Module 2. 依然选择springboot工程 3. 老规矩起个名字 4. 勾选注册中心客户端 5. 勾选zuul网关模块 6. 编写配置文件 server: # 服务端口号 port: 8085 spring: application: # 服务名称 - 服务之间使用名称进行通讯 name: service-zuul eureka: client

springcloud zuul 网关

zuul网关简介 Zuul 网关的核心 是系列过滤器,可以在 Http 请求发起和响应返回期间执行 系列的过滤器. Zuul 包括以下 四种过滤器: 1,PRE 过滤器 它是在请求路由到具体的服务之前执行的,这种类型的过滤器可 以做安全验证,例如身份验证. 参数验证等. 2,ROUTING 过滤器 它用于将请求路由到具体的微服务 .在默认情况下,它使用Http Client 进行网络请求. 3,POST 过滤器:它是在请求己被路由到微服务后执行的,一 般情况下,用作收集统计信息.指标,以及将响

JAVA中的异常(异常处理流程、异常处理的缺陷)

异常处理流程 1)首先由try{...}catch(Exception e){ System.out.println(e); e.printStackTrace(); }finally{...}结构 2)当JVM遇到异常时,会产生一个Exception对象 或 继承自Exception的子类的对象. 3)将异常对象向上层(调用它的代码块)抛出,知道碰到一个catch块(作相应处理) 或 一直抛到了最外层(导致程序异常终止).(并停止异常之后的代码的执行,但是finally块中的代码还会执行!换句

Spring Cloud(Dalston.SR5)--Zuul 网关-Hystrix 回退

当我们对网关进行配置让其调用集群的服务时,将会执行 Ribbon 路由过滤器,该过滤器在进行转发时会封装为一个 Hystrix 命令予以执行,Hystrix 命令具有容错的功能,如果"源服务"出现问题(例如超时),那边所执行的 Hystrix 命令将会触发回退,我们需要实现 org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider 接口,该接口主要需要实现 getRoute 方法 .fallbac

Spring Cloud(Dalston.SR5)--Zuul 网关-微服务集群

通过 url 映射的方式来实现 zuul 的转发有局限性,比如每增加一个服务就需要配置一条内容,另外后端的服务如果是动态来提供,就不能采用这种方案来配置了.实际上在实现微服务架构时,服务名与服务实例地址的关系在 eureka server 中已经存在了,所以只需要将Zuul注册到 eureka server上去发现其他服务,就可以实现对 serviceId 的映射,并且启用了 eureka server 同时也会启用 ribbon 对服务进行负载均衡调用,加入 Zuul 到微服务集群架构图如下:

Spring Cloud微服务Ribbon负载均衡/Zuul网关使用

客户端负载均衡,当服务节点出现问题时进行调节或是在正常情况下进行 服务调度.所谓的负载均衡,就是当服务提供的数量和调用方对服务进行 取舍的调节问题,在spring cloud中是通过Ribbon来解决的.还有另外一 种途径是通过服务端的负载均衡Nginx来解决.Ribbon是客户端的负载均 衡,通过Eureka来获取所有的服务的数量,客户端来调用服务时,Ribbon 通过一系列的算法来进行调节,选择哪个服务来进行调用.默认无需对 Ribbon进行配置,它会采用默认的算法进行负载均衡.可以对负载均

SpringCloud Zuul网关的简单理解

Zuul网关功能 请求路由.服务路由.请求过滤 请求路由 参数配置如下所示,所有能够配置path规则的请求,都会被zuul网关转发到对应的url上. zuul.routes.user-service.path=/user-service/** zuul.routes.user-service.url=http://178.69.1.39:9104/ 服务路由 参数配置如下所示,zuul会对服务user-service进行路由,所有能够配置path规则的请求,都会被zuul网关转发到serivce