亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

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

2019-11-26 09:43:04
字體:
來源:轉載
供稿:網友

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("http://", "/");      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 這兩個了,一個是處理錯誤,一個是處理成功的結果

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国内外成人免费激情在线视频网站| 久久男人av资源网站| 国产精品亚洲第一区| 亚洲一区精品电影| 亚洲国产精品国自产拍av秋霞| 亚洲免费视频网站| 日韩小视频在线| 伊人激情综合网| 久久精品电影网站| 亚洲国产古装精品网站| 国产精品久久久av久久久| 国产精品观看在线亚洲人成网| 精品亚洲一区二区三区四区五区| 日韩精品免费在线视频观看| 午夜精品久久久99热福利| 欧美激情三级免费| 亚洲欧洲在线免费| 成人疯狂猛交xxx| 国产成人精品优优av| 2020国产精品视频| 狠狠躁天天躁日日躁欧美| 国产精品久久久久久久久借妻| 亚洲综合大片69999| 亚洲毛片在线观看.| 亚洲电影成人av99爱色| 国产一区二区视频在线观看| 日韩欧美在线观看视频| 一区二区在线视频播放| 美日韩精品免费观看视频| 亚洲午夜未删减在线观看| 国产精品日韩专区| 国产精品狠色婷| www高清在线视频日韩欧美| 国产精品入口尤物| 精品国内自产拍在线观看| 91av网站在线播放| 国产精品扒开腿做| 成人精品一区二区三区| 日本韩国在线不卡| 成人有码在线视频| 国产精品福利久久久| 欧美亚洲午夜视频在线观看| 国产精品久久久999| 亚洲福利影片在线| 国产香蕉一区二区三区在线视频| 欧美色欧美亚洲高清在线视频| 久热爱精品视频线路一| 久久免费视频观看| 亚洲精品资源美女情侣酒店| 亚洲国产欧美一区二区丝袜黑人| 欧美激情第一页xxx| 68精品久久久久久欧美| 中文字幕亚洲欧美一区二区三区| 久久伊人免费视频| 精品国产自在精品国产浪潮| 午夜美女久久久久爽久久| 午夜剧场成人观在线视频免费观看| 欧美大荫蒂xxx| 91色视频在线观看| 欧美精品久久久久久久久| 欧美日韩一区二区三区在线免费观看| 亚洲欧美在线播放| 久久成人精品电影| 国产不卡av在线| 成人激情视频小说免费下载| 影音先锋欧美精品| 成人疯狂猛交xxx| 深夜精品寂寞黄网站在线观看| 日韩欧美国产中文字幕| 精品无人区乱码1区2区3区在线| 91九色国产社区在线观看| 91情侣偷在线精品国产| 91亚洲国产精品| 久久久国产精品亚洲一区| 国产91精品视频在线观看| 亚洲天天在线日亚洲洲精| 中文字幕国产亚洲2019| 精品偷拍各种wc美女嘘嘘| 亚洲男人的天堂网站| 日韩欧美大尺度| 91精品国产色综合久久不卡98| 久久久精品在线观看| 亚洲国产小视频在线观看| 亚洲美女精品久久| 国产91在线高潮白浆在线观看| 91久久精品一区| 一区二区三区视频观看| 亚洲伦理中文字幕| 国产性猛交xxxx免费看久久| 精品日本美女福利在线观看| 国产欧美精品一区二区三区介绍| 欧美一级淫片videoshd| 日产日韩在线亚洲欧美| 国产黑人绿帽在线第一区| 亚洲激情中文字幕| 日韩视频在线一区| 国产精品一区二区三区免费视频| 欧美伊久线香蕉线新在线| 久久这里有精品| 尤物tv国产一区| 国产精品无码专区在线观看| 最近2019年好看中文字幕视频| 97在线观看视频国产| 亚洲视频日韩精品| 欧美激情精品久久久久久变态| 日韩亚洲国产中文字幕| 亚洲成人中文字幕| 欧美一性一乱一交一视频| 欧美激情乱人伦一区| 亚洲情综合五月天| 欧美日韩成人黄色| 国产精品一区二区三区免费视频| 久久伊人精品视频| 亚洲欧美日韩网| 九九精品视频在线观看| 久久99国产精品久久久久久久久| 欧美日韩在线影院| 亚洲国产高潮在线观看| 国产亚洲一区精品| 久久精品欧美视频| 一区二区三区精品99久久| 久久久www成人免费精品| 亚洲国产中文字幕久久网| 久久久www成人免费精品张筱雨| 久久亚洲精品视频| 欧美一区在线直播| 日韩精品极品在线观看| 一区二区三区视频免费在线观看| 亚洲午夜色婷婷在线| 91精品国产高清自在线| 精品国产鲁一鲁一区二区张丽| 亚洲福利在线观看| 精品无码久久久久久国产| 亚洲黄色有码视频| 国产成人精品久久二区二区91| 亚洲tv在线观看| 日韩精品免费在线播放| 夜色77av精品影院| 久久精品精品电影网| 91精品国产综合久久香蕉| 国产亚洲成av人片在线观看桃| 91在线中文字幕| 中文字幕免费精品一区| 日韩精品高清视频| 97精品国产97久久久久久| 日韩电影中文字幕在线| 91在线无精精品一区二区| 亚洲性av网站| 国产日产欧美a一级在线| 日本aⅴ大伊香蕉精品视频| 国产深夜精品福利| 国内精品视频一区| 日韩美女在线看| 欧美性做爰毛片| 欧美性受xxxx白人性爽| 成人av番号网| 亚洲第一中文字幕| 国产精品国语对白| 亚洲性线免费观看视频成熟| 国产有码一区二区| 亚洲高清av在线| 久久精品视频导航| 国产在线999| 欧美激情中文字幕在线|