「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」
一. 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也可以看一下, 然后看看他们之间的加载顺序.




近期评论