一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - Java教程 - 淺談Spring Cloud zuul http請求轉發原理

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

2021-05-27 11:30David_jim Java教程

這篇文章主要介紹了淺談Spring Cloud zuul http請求轉發原理,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

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

先來看下zuulservletfilter的實現片段

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@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:

?
1
2
3
void postrouting() throws zuulexception {
   zuulrunner.postroute();
 }

同時 zuulrunner再來調用

?
1
2
3
public void postroute() throws zuulexception {
  filterprocessor.getinstance().postroute();
}

最終調用 filterprocessor runfilters

?
1
2
3
4
5
6
7
8
9
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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的定義

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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的一個抽象方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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來作轉發

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
@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中的判斷

?
1
2
3
4
5
@override
public boolean shouldfilter() {
  return requestcontext.getcurrentcontext().getroutehost() != null
      && requestcontext.getcurrentcontext().sendzuulresponse();
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@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 這兩個了,一個是處理錯誤,一個是處理成功的結果

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

原文鏈接:https://www.jianshu.com/p/295e51bc1518

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 精品视频在线免费播放 | 日本道色综合久久影院 | 久久免费观看视频 | 好紧水好多| 亚洲精品国精品久久99热 | 午夜影院在线免费观看 | 久久久无码精品亚洲A片猫咪 | 欧美一区二区三区免费观看视频 | 亚洲天堂网站 | 国产成人99久久亚洲综合精品 | 男gay男gay男gay野外 | 国产一二三区视频 | 国外成品精品1688 | 女同志freelesvoices| 福利视频导航大全 | 加勒比久草 | 久久精品观看影院2828 | 极品妖艳许清赵丽全文免费阅读 | 日韩一区三区 | 日本美女视频韩国视频网站免费 | 99精品网站 | 久久精品热99看 | 91碰碰| 亚洲福利一区 | 日本阿v精品视频在线观看 日本xxx片免费高清在线 | 风间由美一区二区av101 | 国产伦久视频免费观看视频 | 黑人巨大和日本娇小中出 | 人妖女天堂视频在线96 | 日本中文字幕在线视频 | 久久丫线这里只精品 | 任你操视频在线观看 | 日本xx高清视频免费观看 | 日本亚欧乱色视频在线观看 | 无限在线观看视频大全免费高清 | 荡女淫春2未删减版 | 福利姬 magnet | 午夜亚洲WWW湿好大 午夜想想爱 | 手机在线观看精品国产片 | 久久综合中文字幕佐佐木希 | 亚洲天堂精品在线观看 |