麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 開發 > Java > 正文

淺談Spring Cloud zuul http請求轉發原理

2024-07-14 08:42:06
字體:
來源:轉載
供稿:網友

spring cloud 網關,依賴于netflix 下的zuul 組件

zuul 的流程是,自定義 了ZuulServletFilter和zuulServlet兩種方式,讓開發者可以去實現,并調用

先來看下ZuulServletFilter的實現片段

 @Override  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {    try {      init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);      try {        preRouting();      } catch (ZuulException e) {        error(e);        postRouting();        return;      }            // Only forward onto to the chain if a zuul response is not being sent      if (!RequestContext.getCurrentContext().sendZuulResponse()) {        filterChain.doFilter(servletRequest, servletResponse);        return;      }            try {        routing();      } catch (ZuulException e) {        error(e);        postRouting();        return;      }      try {        postRouting();      } catch (ZuulException e) {        error(e);        return;      }    } catch (Throwable e) {      error(new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_FROM_FILTER_" + e.getClass().getName()));    } finally {      RequestContext.getCurrentContext().unset();    }  }

從上面的代碼可以看到,比較關心的是preRouting、routing,postRouting三個方法 ,這三個方法會調用 注冊為ZuulFilter的子類,首先來看下這三個方法

preRouting: 是路由前會做一些內容

routing():開始路由事項

postRouting:路由結束,不管是否有錯誤都會經過該方法

那這三個方法是怎么和ZuulFilter聯系在一起的呢?

先來分析下 preRouting:

 void postRouting() throws ZuulException {    zuulRunner.postRoute();  }

同時 ZuulRunner再來調用

  public void postRoute() throws ZuulException {    FilterProcessor.getInstance().postRoute();  }

最終調用 FilterProcessor 的 runFilters

  public void preRoute() throws ZuulException {    try {      runFilters("pre");    } catch (ZuulException e) {      throw e;    } catch (Throwable e) {      throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName());    }  }

看到了runFilters 是通過 filterType(pre ,route ,post )來過濾出已經注冊的 ZuulFilter:

 public Object runFilters(String sType) throws Throwable {    if (RequestContext.getCurrentContext().debugRouting()) {      Debug.addRoutingDebug("Invoking {" + sType + "} type filters");    }    boolean bResult = false;    //通過sType獲取 zuulFilter的列表    List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);    if (list != null) {      for (int i = 0; i < list.size(); i++) {        ZuulFilter zuulFilter = list.get(i);        Object result = processZuulFilter(zuulFilter);        if (result != null && result instanceof Boolean) {          bResult |= ((Boolean) result);        }      }    }    return bResult;  }

再來看下 ZuulFilter的定義

public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> {  private final DynamicBooleanProperty filterDisabled =      DynamicPropertyFactory.getInstance().getBooleanProperty(disablePropertyName(), false);  /**   * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,   * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.   * We also support a "static" type for static responses see StaticResponseFilter.   * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)   *   * @return A String representing that type   */  abstract public String filterType();  /**   * filterOrder() must also be defined for a filter. Filters may have the same filterOrder if precedence is not   * important for a filter. filterOrders do not need to be sequential.   *   * @return the int order of a filter   */  abstract public int filterOrder();  /**   * By default ZuulFilters are static; they don't carry state. This may be overridden by overriding the isStaticFilter() property to false   *   * @return true by default   */  public boolean isStaticFilter() {    return true;  }

只列出了一部分字段,但可以看到filterType和filterOrder兩個字段,這兩個分別是指定filter是什么類型,排序

這兩個決定了實現的ZuulFilter會在什么階段被執行,按什么順序執行

當選擇好已經注冊的ZuulFilter后,會調用ZuulFilter的runFilter

 public ZuulFilterResult runFilter() {    ZuulFilterResult zr = new ZuulFilterResult();    if (!isFilterDisabled()) {      if (shouldFilter()) {        Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());        try {          Object res = run();          zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);        } catch (Throwable e) {          t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");          zr = new ZuulFilterResult(ExecutionStatus.FAILED);          zr.setException(e);        } finally {          t.stopAndLog();        }      } else {        zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);      }    }    return zr;  }

其中run 是一個ZuulFilter的一個抽象方法

public interface IZuulFilter {  /**   * a "true" return from this method means that the run() method should be invoked   *   * @return true if the run() method should be invoked. false will not invoke the run() method   */  boolean shouldFilter();  /**   * if shouldFilter() is true, this method will be invoked. this method is the core method of a ZuulFilter   *   * @return Some arbitrary artifact may be returned. Current implementation ignores it.   */  Object run();}  

所以,實現ZuulFilter的子類要重寫 run方法,我們來看下 其中一個階段的實現 PreDecorationFilter 這個類是Spring Cloud封裝的在使用Zuul 作為轉發的代碼服務器時進行封裝的對象,目的是為了決定當前的要轉發的請求是按ServiceId,Http請求,還是forward來作轉發

@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("requestURI", route.getPath());        ctx.put("proxy", 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", route.getRetryable());        }        // 如果配置的轉發地址是http開頭,會設置 RouteHost        if (location.startsWith("http:") || location.startsWith("https:")) {          ctx.setRouteHost(getUrl(location));          ctx.addOriginResponseHeader("X-Zuul-Service", location);        }         // 如果配置的轉發地址forward,則會設置forward.to        else if (location.startsWith("forward:")) {          ctx.set("forward.to",              StringUtils.cleanPath(location.substring("forward:".length()) + route.getPath()));          ctx.setRouteHost(null);          return null;        }        else {           // 否則以serviceId進行轉發          // set serviceId for use in filters.route.RibbonRequest          ctx.set("serviceId", location);          ctx.setRouteHost(null);          ctx.addOriginResponseHeader("X-Zuul-ServiceId", location);        }        if (this.properties.isAddProxyHeaders()) {          addProxyHeaders(ctx, route);          String xforwardedfor = ctx.getRequest().getHeader("X-Forwarded-For");          String remoteAddr = ctx.getRequest().getRemoteAddr();          if (xforwardedfor == null) {            xforwardedfor = remoteAddr;          }          else if (!xforwardedfor.contains(remoteAddr)) { // Prevent duplicates            xforwardedfor += ", " + remoteAddr;          }          ctx.addZuulRequestHeader("X-Forwarded-For", xforwardedfor);        }        if (this.properties.isAddHostHeader()) {          ctx.addZuulRequestHeader("Host", toHostHeader(ctx.getRequest()));        }      }    }    else {      log.warn("No route found for uri: " + requestURI);      String fallBackUri = requestURI;      String fallbackPrefix = this.dispatcherServletPath; // default fallback                                // servlet is                                // DispatcherServlet      if (RequestUtils.isZuulServletRequest()) {        // remove the Zuul servletPath from the requestUri        log.debug("zuulServletPath=" + this.properties.getServletPath());        fallBackUri = fallBackUri.replaceFirst(this.properties.getServletPath(), "");        log.debug("Replaced Zuul servlet path:" + fallBackUri);      }      else {        // remove the DispatcherServlet servletPath from the requestUri        log.debug("dispatcherServletPath=" + this.dispatcherServletPath);        fallBackUri = fallBackUri.replaceFirst(this.dispatcherServletPath, "");        log.debug("Replaced DispatcherServlet servlet path:" + fallBackUri);      }      if (!fallBackUri.startsWith("/")) {        fallBackUri = "/" + fallBackUri;      }      String forwardURI = fallbackPrefix + fallBackUri;      forwardURI = forwardURI.replaceAll("//", "/");      ctx.set("forward.to", forwardURI);    }    return null;  }

這個前置處理,是為了后面決定以哪種ZuulFilter來處理當前的請求 ,如 SimpleHostRoutingFilter,這個的filterType是post ,當 ``PreDecorationFilter設置了requestContext中的 RouteHost,如 SimpleHostRoutingFilter中的判斷

  @Override  public boolean shouldFilter() {    return RequestContext.getCurrentContext().getRouteHost() != null        && RequestContext.getCurrentContext().sendZuulResponse();  }

在 SimpleHostRoutingFilter中的run中,真正實現地址轉發的內容,其實質是調用 httpClient進行請求

@Override  public Object run() {    RequestContext context = RequestContext.getCurrentContext();    HttpServletRequest request = context.getRequest();    MultiValueMap<String, String> headers = this.helper        .buildZuulRequestHeaders(request);    MultiValueMap<String, String> params = this.helper        .buildZuulRequestQueryParams(request);    String verb = getVerb(request);    InputStream requestEntity = getRequestBody(request);    if (request.getContentLength() < 0) {      context.setChunkedRequestBody();    }    String uri = this.helper.buildZuulRequestURI(request);    this.helper.addIgnoredHeaders();    try {      HttpResponse response = forward(this.httpClient, verb, uri, request, headers,          params, requestEntity);      setResponse(response);    }    catch (Exception ex) {      context.set(ERROR_STATUS_CODE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);      context.set("error.exception", ex);    }    return null;  }

最后如果是成功能,會調用 注冊 為post的ZuulFilter ,目前有兩個 SendErrorFilter 和 SendResponseFilter 這兩個了,一個是處理錯誤,一個是處理成功的結果

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 色婷婷久久久久久 | 一级毛片在线免费播放 | asian gaysex| 香蕉视频网站在线观看 | 国产一区视频在线观看免费 | 久久99国产视频 | 国产99免费 | 国产91久久久久久 | japanese hot milf free av | 午夜免费一区 | 色柚视频网站ww色 | 久久精品亚洲精品国产欧美kt∨ | 一级毛片免费高清视频 | 素人视频在线观看免费 | 性插视频| 中文字幕在线观看视频一区 | 久久精品视频日本 | 久久成人视屏 | av电影在线网 | 国产精品视频自拍 | 91精品视频免费 | 欧美一级美片在线观看免费 | 亚洲综合视频一区 | 手机免费看一级片 | 粉嫩av一区二区三区四区在线观看 | 国产精品免费一区二区三区四区 | 欧美色性 | 在线播放免费人成毛片乱码 | 超碰97在线人人 | 午夜激情视频网站 | 毛片毛片 | 毛片免费视频观看 | 国产二区三区在线播放 | 羞羞电影网 | 中文字幕精品久久 | 超碰人人做人人爱 | 久久不射电影 | 永久免费在线观看av | 中文有码一区二区 | 精品国产看高清国产毛片 | 中午字幕无线码一区2020 |