一、Zuul
Zuul是通过Servlet来实现的,Zuul通过自定义的ZuulServlet(类似于Spring MVC的DispatcherServlet)来对请求进行控制(一系列过滤器处理Http请求)。
所有的Request都要经过ZuulServlet的处理,三个核心的方法preRoute(),route(), postRoute(),zuul对request处理逻辑都在这三个方法里,ZuulServlet交给ZuulRunner去执行。
ZuulRunner直接将执行逻辑交由FilterProcessor处理,ZuulServlet、ZuulRunner、FilterProcessor都是单例。
FilterProcessor对filter的处理逻辑。
1.根据Type获取所有输入该Type的filter,List<ZuulFilter> list。
2.遍历该list,执行每个filter的处理逻辑,processZuulFilter(ZuulFilter filter)。
3.RequestContext对每个filter的执行状况进行记录,此处的执行状态主要包括其执行时间、以及执行成功或者失败,若失败则对异常封装后抛出。
4.zuul框架对每个filter的执行结果都没有太多的处理,没把上一filter的执行结果交由下一个将要执行的filter,仅记录执行状态,如果执行失败抛出异常并终止执行。
1、Zuul过滤器的功能
1.身份验证和安全性 - 确定每个资源的身份验证要求并拒绝不满足这些要求的请求。
2.洞察和监控 - 在边缘跟踪有意义的数据和统计数据,以便为我们提供准确的生产视图。
3.动态路由 - 根据需要动态地将请求路由到不同的后端群集。
4.压力测试 - 逐渐增加群集的流量以衡量性能。
5.负载分配 - 为每种类型的请求分配容量并删除超过限制的请求。
6.静态响应处理 - 直接在边缘构建一些响应,而不是将它们转发到内部集群。
2、Zuul 生命周期(四类过滤)
1.PRE: 在请求被路由之前调用。可在集群中选择请求的微服务、认证鉴权,限流等。
2.ROUTING: 将请求路由到微服务。可构建发送给微服务的请求,并使用Apache HttpClient或 Ribbon请求微服务,现在也支持OKHTTP。
3.POST: 在路由到微服务以后执行。可在这种过滤中处理逻辑,如收集统计信息和指标、将响应从微服务发送给客户端等。
4.ERROR: 在其他阶段发生错误时执行该过滤器。可做全局异常处理。
3、Zuul的使用
1.配置
server:
port: 80
spring:
application:
name: demo-zuul
eureka:
client:
enabled: true #该客户端是否可用
service-url:
defaultZone: http://localhost:8761/eureka #注册中心地址
register-with-eureka: true #注册该服务,默认为true
fetch-registry: true #获取服务列表,默认为true
2.启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.discovery.PatternServiceRouteMapper;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableZuulProxy//开启网关功能
public class DemoZuulApplication {
public static void main(String[] args) {
SpringApplication.run(DemoZuulApplication.class, args);
}
//配置动态路由规则
@Bean
public PatternServiceRouteMapper getPatternServiceRouteMapper() {
return new PatternServiceRouteMapper("(?<name>^.+)", "${name}");
}
}
3.写自己的过滤器
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
@Component
public class TokenFilter extends ZuulFilter {
/**
* 拦截类型,4种类型 pre route error post
*/
@Override
public String filterType() {
// FilterConstants.PRE_TYPE;
// FilterConstants.ROUTE_TYPE;
// FilterConstants.ERROR_TYPE;
// FilterConstants.POST_TYPE;
return FilterConstants.PRE_TYPE;
}
/**
* 该过滤器在所有过滤器的执行顺序值,值越小,越前面执行
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 是否拦截
*/
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
// RequestContext ctx = RequestContext.getCurrentContext();
// ctx.getBoolean("isOk");
HttpServletRequest request = ctx.getRequest();
String requestURI = request.getRequestURI();
//排除拦截的url
if (requestURI.equals("/demo-member/user/loadBalance")) {
return false;
}
return true;
}
/**
* 过滤器具体的业务逻辑
*/
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String token = request.getParameter("token");
// ctx.set("isOk",true); // 可以在上下文里面设置一个key,在下一次拦截时,就可以获取到
if (null == token) {
ctx.setResponseBody("token is null");
ctx.setResponseStatusCode(400);
ctx.setSendZuulResponse(false);
return null;
}
if (!"123456".equals(token)) {
ctx.setResponseBody("token is error");
ctx.setResponseStatusCode(400);
ctx.setSendZuulResponse(false);
return null;
}
ctx.setSendZuulResponse(true);
return null;
}
}