一. zuul路由的原理
从客户端的请求过来了, 全部走网关, 网关经过处理, 将请求分发给微服务应用, 微服务处理完请求以后, 将结果返回给网关. 网关在响应给客户端.
二. 我们怎么实现zuul的效果?
用户访问进来 -> preRouterFilter -> routerFilter -> PostRouterFilter -> 微服务
zuul的核心本质就是filter, Zuul的所有功能都是在Filter里面实现
Zuul 解析我们的url来决定我们去访问哪个微服务, 这是一个过滤器
Zuul 去发请求访问微服务, 这也是一个过滤器
Zuul 给用户响应数据, 这也是一个过滤器
1. 四种过滤器的关系
这是一个网关过滤器, 包含四种过滤器类型.
当一个请求过来的时候, 他会先进入pre, 然后进入routing , 最后进入post过滤器. 三个过滤器任何一个发生异常, 都进入error routing过滤器
2. 共享RequestContext
zuul中所有的filter在同一个线程里共享RequestContext.
zuulFilter通过RequestContext共享访问的变量
三. 用户访问zuul的入口
思考这个问题, 我们可以类别springMVC. 在springMVC中, 用户请求的入口会进入到哪里呢? DispatcherServlet.
那么zuul也是一样的, 他的入口也是servlet, 名字叫做ZuulServlet
下面, 我们来看一下zuul-core包的核心代码
在这里面有一个http文件夹, 在http文件中就是处理用户过来的请求的
zuul的入口是zuulServlet
在servlet中, 我们知道其执行的主方法是service. 因此我们来看看主要的核心方法service()
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
try {
// 初始化http请求
this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
// 所有请求都会建立一个RequestContent
RequestContext context = RequestContext.getCurrentContext();
// 给当前的访问, 设置一个处理引擎
context.setZuulEngineRan();
try {
// 首先执行的是前置过滤器, 从所有过滤器中过滤出pre类型的过滤器, 并执行
// 前置过滤器通常处理用户参数校验, 权限校验, 限流, 熔断等
this.preRoute();
} catch (ZuulException var12) {
// 如果pre filter发生异常, 则进入error过滤器
this.error(var12);
// 在进入post route过滤器
// 用户的响应数据是通过post filter返回给客户端的
this.postRoute();
return;
}
try {
// route filter的主要工作是, 将用户的请求, 转变成有zuul构造的请求, 去访问微服务
this.route();
} catch (ZuulException var13) {
this.error(var13);
this.postRoute();
return;
}
try {
// 将微服务响应的数据, 返回给客户端
this.postRoute();
} catch (ZuulException var11) {
this.error(var11);
}
} catch (Throwable var14) {
this.error(new ZuulException(var14, 500, "UNHANDLED_EXCEPTION_" + var14.getClass().getName()));
} finally {
RequestContext.getCurrentContext().unset();
}
}
我们来看一下源码.
源码流程如上
下面我们以前置过滤器为例, 说明过滤器执行的原理
四. zuul有哪些关键的filter?
我们来看看都spring自己加载的过滤器有哪些?
spring会自动扫描注解, 加载一下了两个类的所有过滤器
ZuulProxyAutoConfiguration 类里面看核心的关键filter
ZuulServerAutoConfiguration 里面的核心的关键filter
这是在ZuulProxyAutoConfiguration注册的过滤器
这是在ZuulServierAutoConfiguration中注册的过滤器
汇总:
pre过滤器:
PreDecorationFilter
ServletDetectionFilter
FormBodyWrapperFilter
DebugFilter
Servlet30WrapperFilter
routing 过滤器
RibbonRoutingFilter
SimpleHostRoutingFilter
post过滤器
SendResponseFilter
SendForwardFilter
error过滤器
SendErrorFilter
其实有这么多个过滤器, error过滤器就是不说, 有异常会进入到error过滤器
那么其他过滤器中最重要的就是一下三个.
一个用户请求过了, 首先要有一个前置过滤器解析连接, 组装路由.
然后执行route 过滤器跳转到指定的微服务
最后执行post过滤器,将执行的结果返回给用户
1. 下面我们来看看preDecorationFilter过滤器做了什么
通过看源码,我们得到以上信息, 其实这里主要做了一件事, 那就是梳理出后面要跳转到那个微服务的路由信息
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
final String requestURI = this.urlPathHelper
.getPathWithinApplication(ctx.getRequest());
Route route = this.routeLocator.getMatchingRoute(requestURI);
if (route != null) {
String location = route.getLocation();
if (location != null) {
ctx.put(REQUEST_URI_KEY, route.getPath());
ctx.put(PROXY_KEY, route.getId());
if (!route.isCustomSensitiveHeaders()) {
this.proxyRequestHelper.addIgnoredHeaders(
this.properties.getSensitiveHeaders().toArray(new String[0]));
}
else {
this.proxyRequestHelper.addIgnoredHeaders(
route.getSensitiveHeaders().toArray(new String[0]));
}
if (route.getRetryable() != null) {
ctx.put(RETRYABLE_KEY, route.getRetryable());
}
if (location.startsWith(HTTP_SCHEME + ":")
|| location.startsWith(HTTPS_SCHEME + ":")) {
ctx.setRouteHost(getUrl(location));
ctx.addOriginResponseHeader(SERVICE_HEADER, location);
}
else if (location.startsWith(FORWARD_LOCATION_PREFIX)) {
ctx.set(FORWARD_TO_KEY,
StringUtils.cleanPath(
location.substring(FORWARD_LOCATION_PREFIX.length())
+ route.getPath()));
ctx.setRouteHost(null);
return null;
}
else {
// set serviceId for use in filters.route.RibbonRequest
ctx.set(SERVICE_ID_KEY, location);
ctx.setRouteHost(null);
ctx.addOriginResponseHeader(SERVICE_ID_HEADER, location);
}
if (this.properties.isAddProxyHeaders()) {
addProxyHeaders(ctx, route);
String xforwardedfor = ctx.getRequest()
.getHeader(X_FORWARDED_FOR_HEADER);
String remoteAddr = ctx.getRequest().getRemoteAddr();
if (xforwardedfor == null) {
xforwardedfor = remoteAddr;
}
else if (!xforwardedfor.contains(remoteAddr)) { // Prevent duplicates
xforwardedfor += ", " + remoteAddr;
}
ctx.addZuulRequestHeader(X_FORWARDED_FOR_HEADER, xforwardedfor);
}
if (this.properties.isAddHostHeader()) {
ctx.addZuulRequestHeader(HttpHeaders.HOST,
toHostHeader(ctx.getRequest()));
}
}
}
else {
log.warn("No route found for uri: " + requestURI);
String forwardURI = getForwardUri(requestURI);
ctx.set(FORWARD_TO_KEY, forwardURI);
}
return null;
}
2. RibbonRoutintFilter过滤器
这是zuul中非常重要的一个过滤器, 他是执行路由转发到微服务的工作. 具体的流程如上
3. SendResponseFilter过滤器
这个过滤器是将微服务响应的请求回传给用户
其他的filter也可以看一下, 然后看看他们之间的加载顺序.