4. 网关的原理及源码

一. 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也可以看一下, 然后看看他们之间的加载顺序. 

 

posted @ 2020-06-23 19:33  盛开的太阳  阅读(1100)  评论(0)    收藏  举报