微服务--Zuul过滤器

Zuul的核心


  • 上文也提到了Zuul的核心是一系列过滤器,用来实现对外服务请求的控制。
  • Zuul包括以下4种过滤器,分别是“PRE”、“ROUTING”、“POST”、“ERROR”
    在这里插入图片描述
    • PRE:在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
    • ROUTING:将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
    • POST:在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
    • ERROR:在其他阶段发生错误时执行该过滤器。
  • 执行顺序:pre -> routing -> post -> error
  • Zuul采用动态读取、编译和运行过滤器。过滤器质检不能直接通信,通过RequestContext对象来共享数据,每个请求都会创建一个RequestContext对象。
  • Zuul过滤器包含以下属性
    • Type:类型 ;即上述4种类型
    • Execution Order:执行吮吸,Order越小,越先执行
    • Criteria (shouldFilter):Filter执行所需的条件,指定Filter是否执行
    • Run:行动,执行Filter的具体逻辑内容

Zuul的工作原理


执行机制
  • request进入Zuul网关服务,先进PreFilter,进行一些列的验证、操作或判断;
  • 交给RoutingFilter进行路由转发,到具体的服务实例进行逻辑处理,返回数据;
  • 服务处理完,由PostFilter进行处理,该类型的Filter处理完
  • 将Response信息返回给客户端。
ZuulServlet
  • ZuulServlet是Zuul的核心Servlet
  • 作用是初始化ZuulFilter,编排ZuulFilter的执行顺序。
  • 以下是ZuulServlet的service()方法
    public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
        try {
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

            // Marks this request as having passed through the "Zuul engine", as opposed to servlets
            // explicitly bound in web.xml, for which requests will not have the same data attached
            RequestContext context = RequestContext.getCurrentContext();
            context.setZuulEngineRan();

            try {
                preRoute();
            } catch (ZuulException e) {
                error(e);
                postRoute();
                return;
            }
            try {
                route();
            } catch (ZuulException e) {
                error(e);
                postRoute();
                return;
            }
            try {
                postRoute();
            } catch (ZuulException e) {
                error(e);
                return;
            }

        } catch (Throwable e) {
            error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
        } finally {
            RequestContext.getCurrentContext().unset();
        }
    }
  • 从代码中看出来,先执行preRoute();出异常则执行error(e)和postRoute()。然后执行route();最后执行postRoute();中间出现异常执行error()

自定义Filter


  • 集成ZuulFilter类
  • 实现filterType()、 filterOrder()、 shouldFilter()、 run() 4个方法
public class CustomizeFilter extends ZuulFilter {
    @Override
    public String filterType() {
    	// 定义filter的类型,有pre、route、post、error四种
        return null;
    }

    @Override
    public int filterOrder() {
    	// 定义filter的顺序,数字越小表示顺序越高,越先执行
        return 0;
    }

    @Override
    public boolean shouldFilter() {
    	// 表示是否需要执行该filter,true表示执行,false表示不执行
        return false;
    }

    @Override
    public Object run() throws ZuulException {
    	// ilter需要执行的具体操作
        return null;
    }
}
自定义PreFilter
  • 自定义一个Pre类型的Filter,可以做校验。实验程序中校验token必传
/**
 * 路由前置Filter:<Br>
 * pre:可以在请求被路由之前调用 <br>
 * 一般作用在路由之前做一些鉴权 校验的功能
 *
 *
 * @author yanbin
 * @since 2019/9/5 14:16
 *
 */
@Component
public class PreFilter extends ZuulFilter {
	@Override
	public String filterType() {
		// 过滤器类型
		return FilterConstants.PRE_TYPE;
	}

	@Override
	public int filterOrder() {
		// 过滤器顺序,数值越小,越先执行
		return 0;
	}

	@Override
	public boolean shouldFilter() {
		// 是否启用这个过滤器,return true 说明执行run()方法
		return false;
	}

	@Override
	public Object run() throws ZuulException {
		RequestContext requestContext = RequestContext.getCurrentContext();
		HttpServletRequest request = requestContext.getRequest();
		String token = request.getParameter("token");
		if (null == token) {
			requestContext.setSendZuulResponse(false);
			requestContext.setResponseStatusCode(403);
			try {
				requestContext.getResponse().getWriter().write("token is empty");
			} catch (IOException e) {
				return null;
			}
		}
		return null;
	}

}
  • 启动调试: 访问:http://127.0.0.1:8888/provider/hello?name=yanbin 不带token
    在这里插入图片描述
自定义PostFilter
  • 定义个Post过滤器,最后改变Response的输出
/**
 * 后置过滤器<br>
 * post:在routing之后被调用<br>
 * 一般作用是打赢响应的时间,返回日志 ;
 *
 *
 * @author yanbin
 * @since 2019/9/5 14:40
 *
 */
@Component
public class PostFilter extends ZuulFilter {
	@Override
	public String filterType() {
		return FilterConstants.POST_TYPE;
	}

	@Override
	public int filterOrder() {
		return 0;
	}

	@Override
	public boolean shouldFilter() {
		return true;
	}

	@Override
	public Object run() throws ZuulException {
		RequestContext ctx = RequestContext.getCurrentContext();
		System.out.println("POST:" + ctx.getResponseBody());

		ctx.setResponseBody("post后置数据");

		// int i = 1 / 0;

		return null;
	}
}
  • 启动调试:访问http://127.0.0.1:8888/provider/hello?name=yanbin&token=1123
    在这里插入图片描述
自定义ErrorFilter
  • 定义Error过滤器,在请求到响应过程中出现异常,进行处理输出
/**
 * 异常过滤器<br>
 * error:处理请求时发生错误时被调用;在post之后<br>
 * 一般用于请求过程中出现异常之后统一的跳转
 *
 *
 * @author yanbin
 * @since 2019/9/5 15:18
 *
 */
@Component
public class ErrorFilter extends ZuulFilter {
	@Override
	public String filterType() {
		return FilterConstants.ERROR_TYPE;
	}

	@Override
	public int filterOrder() {
		return 0;
	}

	@Override
	public boolean shouldFilter() {
		return true;
	}

	@Override
	public Object run() throws ZuulException {
		RequestContext ctx = RequestContext.getCurrentContext();

		System.out.println("Error:" + ctx.getResponseBody());

		ctx.setResponseBody("出现异常");

		return null;
	}
}
  • 启动调试:访问 http://127.0.0.1:8888/provider/hello?name=yanbin&token=1123
  • 报错了在这里插入图片描述
  • 也输出了ErrorFilter中的逻辑
    在这里插入图片描述
  • 介于界面不友好,增加一个 /Error 的请求
/**
 * 异常页面
 *
 *
 * @author yanbin
 * @since 2019/9/5 16:03
 *
 */
@RestController
public class ErrorHandlerController implements ErrorController {
	@Override
	public String getErrorPath() {
		return "/error";
	}

	@RequestMapping("/error")
	public String error() {
		return "出现异常";
	}

}

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值