最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Spring Cloud zuul http請求轉(zhuǎn)發(fā)原理

 更新時間:2018年08月20日 11:54:51   作者:David_jim  
這篇文章主要介紹了淺談Spring Cloud zuul http請求轉(zhuǎn)發(fā)原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

spring cloud 網(wǎng)關(guān),依賴于netflix 下的zuul 組件

zuul 的流程是,自定義 了ZuulServletFilter和zuulServlet兩種方式,讓開發(fā)者可以去實現(xiàn),并調(diào)用

先來看下ZuulServletFilter的實現(xiàn)片段

 @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();
    }
  }

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

preRouting: 是路由前會做一些內(nèi)容

routing():開始路由事項

postRouting:路由結(jié)束,不管是否有錯誤都會經(jīng)過該方法

那這三個方法是怎么和ZuulFilter聯(lián)系在一起的呢?

先來分析下 preRouting:

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

同時 ZuulRunner再來調(diào)用

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

最終調(diào)用 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 )來過濾出已經(jīng)注冊的 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是什么類型,排序

這兩個決定了實現(xiàn)的ZuulFilter會在什么階段被執(zhí)行,按什么順序執(zhí)行

當(dāng)選擇好已經(jīng)注冊的ZuulFilter后,會調(diào)用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();
}  

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

@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());
        }
        // 如果配置的轉(zhuǎn)發(fā)地址是http開頭,會設(shè)置 RouteHost
        if (location.startsWith("http:") || location.startsWith("https:")) {
          ctx.setRouteHost(getUrl(location));
          ctx.addOriginResponseHeader("X-Zuul-Service", location);
        }
         // 如果配置的轉(zhuǎn)發(fā)地址forward,則會設(shè)置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進(jìn)行轉(zhuǎn)發(fā)
          // 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("http://", "/");
      ctx.set("forward.to", forwardURI);
    }
    return null;
  }

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

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

在 SimpleHostRoutingFilter中的run中,真正實現(xiàn)地址轉(zhuǎn)發(fā)的內(nèi)容,其實質(zhì)是調(diào)用 httpClient進(jìn)行請求

@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;
  }

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot將lib和jar分離的操作方法

    springboot將lib和jar分離的操作方法

    本文介紹了如何通過優(yōu)化pom.xml配置來減小Spring Boot項目的jar包大小,主要通過使用spring-boot-maven-plugin和maven-dependency-plugin插件,將依賴庫打包到j(luò)ar中,并通過指定外部lib路徑的方式運行jar,從而減小jar包體積,感興趣的朋友一起看看吧
    2025-02-02
  • SpringBoot3結(jié)合Vue3實現(xiàn)用戶登錄功能

    SpringBoot3結(jié)合Vue3實現(xiàn)用戶登錄功能

    最近項目需求搭建一個結(jié)合Vue.js前端框架和Spring Boot后端框架的登錄系統(tǒng),本文主要介紹了SpringBoot3結(jié)合Vue3實現(xiàn)用戶登錄功能,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • Java?Socket實現(xiàn)聊天室功能

    Java?Socket實現(xiàn)聊天室功能

    這篇文章主要為大家詳細(xì)介紹了Java?Socket實現(xiàn)聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • 解決java讀取EXCEL數(shù)據(jù)變成科學(xué)計數(shù)法的問題

    解決java讀取EXCEL數(shù)據(jù)變成科學(xué)計數(shù)法的問題

    這篇文章主要介紹了解決java讀取EXCEL數(shù)據(jù)變成科學(xué)計數(shù)法的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Java中的concurrenthashmap集合詳細(xì)剖析

    Java中的concurrenthashmap集合詳細(xì)剖析

    這篇文章主要介紹了Java中的concurrenthashmap集合詳細(xì)剖析,有參構(gòu)造后第一次put時會進(jìn)行初始化,由源碼可知,會先判斷所傳入的容量是否>=最大容量的一半,如果滿足條件,就會將容量修改為最大值,反之則會將容量改為所傳入數(shù)*1.5+1,需要的朋友可以參考下
    2023-11-11
  • Java日常練習(xí)題,每天進(jìn)步一點點(18)

    Java日常練習(xí)題,每天進(jìn)步一點點(18)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07
  • springMVC向Controller傳值出現(xiàn)中文亂碼的解決方案

    springMVC向Controller傳值出現(xiàn)中文亂碼的解決方案

    這篇文章主要介紹了springMVC向Controller傳值出現(xiàn)中文亂碼的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • java簡單模仿win10計算器

    java簡單模仿win10計算器

    這篇文章主要為大家詳細(xì)介紹了java簡單模仿win10計算器de,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • java 中自定義OutputFormat的實例詳解

    java 中自定義OutputFormat的實例詳解

    這篇文章主要介紹了java 中 自定義OutputFormat的實例詳解的相關(guān)資料,這里提供實例幫助大家學(xué)習(xí)理解這部分內(nèi)容,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-08-08
  • Jmeter跨線程組傳值調(diào)用實現(xiàn)圖解

    Jmeter跨線程組傳值調(diào)用實現(xiàn)圖解

    這篇文章主要介紹了Jmeter跨線程組傳值調(diào)用實現(xiàn)圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07

最新評論

鹤庆县| 北辰区| 海淀区| 长阳| 安达市| 林州市| 仪陇县| 林甸县| 抚松县| 曲靖市| 乌拉特后旗| 古田县| 微博| 通许县| 永春县| 当阳市| 西吉县| 钦州市| 武川县| 赣榆县| 阳东县| 嘉义市| 麦盖提县| 阿拉善左旗| 汽车| 兴山县| 江川县| 库车县| 山西省| 鄂州市| 调兵山市| 台南市| 霸州市| 金塔县| 黔南| 牡丹江市| 兰考县| 额济纳旗| 安西县| 修武县| 濮阳市|