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也可以看一下, 然后看看他們之間的加載順序. 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM