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

首頁 > 開發 > 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教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲自拍中文字幕| 在线观看不卡av| 色妞欧美日韩在线| 国产精品69久久| 伊人av综合网| 国产欧美日韩精品在线观看| 国产精品久久久久9999| 中文字幕日韩有码| 精品调教chinesegay| 日本一区二区在线播放| 亚洲国产精品成人va在线观看| 亚洲欧洲在线视频| 成年无码av片在线| 国产精品嫩草影院一区二区| 亚洲成人动漫在线播放| 国产91精品久久久久久| 91亚洲国产成人久久精品网站| 欧美性xxxx18| 亚洲欧美日韩精品久久奇米色影视| 久久久精品电影| 97国产一区二区精品久久呦| 国产一区二区三区在线| 欧美xxxx做受欧美| 日韩美女视频免费看| 亚洲精品99久久久久中文字幕| 国产精品96久久久久久| 欧美激情2020午夜免费观看| 亚洲跨种族黑人xxx| 伦伦影院午夜日韩欧美限制| 久久久精品国产亚洲| 丝袜美腿亚洲一区二区| 最好看的2019的中文字幕视频| 亚洲精品v天堂中文字幕| 国产成人精品av在线| 欧美专区国产专区| 日韩免费看的电影电视剧大全| 欧美大片在线看免费观看| 成人网中文字幕| 日韩电影在线观看中文字幕| 成人黄在线观看| 欧美亚洲视频在线看网址| 中文字幕亚洲无线码a| 久久久久久成人| 国产99久久精品一区二区 夜夜躁日日躁| 69久久夜色精品国产69乱青草| 欧美激情视频一区二区三区不卡| 91久久久亚洲精品| 亚洲人成人99网站| 欧美三级免费观看| 亚洲视频日韩精品| 亚洲国产欧美久久| 成人做爰www免费看视频网站| 欧美国产日产韩国视频| 欧美色xxxx| 欧美极品第一页| 国产黑人绿帽在线第一区| 日韩在线观看免费全集电视剧网站| 国产精品美女主播在线观看纯欲| 亚洲第一精品福利| 精品香蕉在线观看视频一| 国产精品91久久久久久| 精品在线欧美视频| 欧美另类极品videosbestfree| 国内精品视频久久| 久久九九全国免费精品观看| 伊人久久久久久久久久久| 7777精品久久久久久| 午夜欧美不卡精品aaaaa| 中文字幕免费精品一区高清| 欧美在线视频一区| y97精品国产97久久久久久| 91国语精品自产拍在线观看性色| 成人免费直播live| 91九色视频在线| 欧美麻豆久久久久久中文| 欧美性精品220| 一区二区三区回区在观看免费视频| 国产精品一区专区欧美日韩| 自拍偷拍亚洲区| 97av在线播放| 亚洲精品资源美女情侣酒店| 国产欧美日韩免费看aⅴ视频| 精品久久久精品| 91性高湖久久久久久久久_久久99| 91精品国产综合久久香蕉| 国产成+人+综合+亚洲欧美丁香花| 日韩高清电影免费观看完整| 成人av在线网址| 亚洲黄色av网站| 国产精品18久久久久久麻辣| 国产精品香蕉国产| 国产一区二区三区在线观看网站| 国产一区二区日韩精品欧美精品| 欧美日韩在线影院| 国产91精品视频在线观看| 国产成人在线视频| 亚洲国产欧美自拍| 国产精品一久久香蕉国产线看观看| 久久夜色精品亚洲噜噜国产mv| 国产97人人超碰caoprom| 亚洲91精品在线观看| 欧美激情亚洲自拍| 91精品视频网站| 国内精品国产三级国产在线专| 136fldh精品导航福利| 欧美成年人视频网站欧美| 日韩精品视频免费| 亚洲精品99久久久久中文字幕| 成人有码在线播放| 91爱视频在线| 亚洲国产精彩中文乱码av在线播放| 午夜精品久久久久久久99热| 91精品国产高清自在线看超| 成人欧美在线观看| 91av视频在线| 欧美亚洲在线播放| 久久精品国产久精国产一老狼| 在线电影欧美日韩一区二区私密| 97视频在线观看免费高清完整版在线观看| 欧美日韩国产123| 国模视频一区二区三区| 欧美激情综合色综合啪啪五月| 亚洲国产成人爱av在线播放| 亚洲激情视频在线播放| 亚洲激情久久久| 最近2019中文字幕mv免费看| 亚洲国产婷婷香蕉久久久久久| 午夜精品美女自拍福到在线| 日韩中文字幕视频在线观看| 国产精品视频最多的网站| 国产精品a久久久久久| 国产成人短视频| 欧美性生交xxxxx久久久| 亚洲精品国产品国语在线| 欧美一级bbbbb性bbbb喷潮片| 久久这里有精品| 国产欧美一区二区三区视频| 亚洲男人天堂2023| 日本亚洲欧美三级| 国产成人短视频| 亚洲国产黄色片| 国产精品国产福利国产秒拍| 日韩在线精品视频| 欧美尺度大的性做爰视频| 欧美激情一区二区三区高清视频| 国产精品一区电影| 91精品国产91久久| 国产一区二区三区18| 九九热视频这里只有精品| 久久久国产一区二区| 亚洲成人av片| 国产一区二区三区高清在线观看| 欧美在线观看日本一区| 2018国产精品视频| 日韩av免费在线看| 亚洲韩国青草视频| 色偷偷888欧美精品久久久| 国产精品v片在线观看不卡| 最近2019好看的中文字幕免费| 91视频国产高清| 57pao国产成人免费| 色爱av美腿丝袜综合粉嫩av| 日日骚久久av| 午夜剧场成人观在线视频免费观看|