spring cloud 之API服務網(wǎng)關(guān)(zuul)


  在微服務場景下,每個微服務都對外暴露了一組細粒度的defuwu服務??蛻舳说恼埱罂赡軙婕暗揭淮姆照{(diào)用,如果將這些服務都暴露客戶端,那么客戶端需要請求不同的微服務才能完成一次業(yè)務處理,增加客戶端的代碼復雜度,除此之外,對于微服務我們可能需要服務調(diào)用進行統(tǒng)一的認證和校驗。

  zuul是基于設(shè)計模式中的facade模式(外觀模式), 將細粒度的服務組合起來提供一個粗粒度的服務,所有服務的入口都統(tǒng)一到一個入口,那么整個服務只需暴露一個API, 對外端屏蔽服務的細節(jié),也減少了客戶端與服務器的網(wǎng)絡(luò)調(diào)用次數(shù)。就是API服務網(wǎng)關(guān)(api-Gateway)服務。
  spring cloud netflix的zuul組件可以做反向代理功能,通過路由尋址將求轉(zhuǎn)發(fā)到后端的粒度服務上,并做統(tǒng)一的邏輯處理

一、zuul介紹

zuul中定義的四中不同生命的過濾器類型:
  1. pre:路由之前
  2. routing:路由之時
  3. post:路由之后
  4. error:發(fā)送錯誤調(diào)用

二、zuul請求路由

zuul的請求路由有點類似于nginx的反向代理,通過指定代理的請求路徑和配置過濾條件來組件一個請求的路由規(guī)則,將符合路由規(guī)則的請求轉(zhuǎn)發(fā)到真正請求的服務上面去。

zuul.routes.record-serve.path=/api/record-server/**
zuul.routes.record-serve.url=http://192.168.1.126:10007/

三、zuul服務名稱路由

zuul通過服務名稱到enurek注冊中心查找到服務對應的IP在路由到指定的服務上面(如何有多個相同名稱的服務,ribbon會進行負載均衡到其中的一個ip上返回)。在路由到對應的服務上面去完成請求操作

zuul:
  routes:
    api-a:
      path: /api-a/**
      serviceId: service-ribbon
    api-b:
      path: /api-b/**
      serviceId: service-feign

四、@EnableZuulServer注解

1.pre類型過濾器

(1)ServletDetectionFilter: 主要是檢測是否是否通過DispatcherServlet控制器進行進行請求,設(shè)置isDispatcherServletRequest參數(shù)

#部分源碼展示
public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        if (!(request instanceof HttpServletRequestWrapper) && this.isDispatcherServletRequest(request)) {
            ctx.set("isDispatcherServletRequest", true);
        } else {
            ctx.set("isDispatcherServletRequest", false);
        }

        return null;
    }

    private boolean isDispatcherServletRequest(HttpServletRequest request) {
        return request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null;
    }

(2)FormBodyWrapperFilter: 解析表單數(shù)據(jù),并為請求重寫編碼
 (3)DebugFilter: 調(diào)試用的過濾器

2.route類型過濾器

SendForwardFilter:該過濾器使用ServletRequestDispatcher轉(zhuǎn)發(fā)請求,轉(zhuǎn)發(fā)位置存儲在RequestContext.getCurrentContext().get("forward.to")中??梢詫⒙酚稍O(shè)置成:

zuul.routes.record-serve.path=/api/record-server/**
zuul.routes.record-serve.url=http://192.168.1.126:10007/

SendForwardFilter部分源碼

 public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        return ctx.containsKey("forward.to") && !ctx.getBoolean("sendForwardFilter.ran", false);
    }

    public Object run() {
        try {
            RequestContext ctx = RequestContext.getCurrentContext();
            String path = (String)ctx.get("forward.to");
            RequestDispatcher dispatcher = ctx.getRequest().getRequestDispatcher(path);
            if (dispatcher != null) {
                ctx.set("sendForwardFilter.ran", true);
                if (!ctx.getResponse().isCommitted()) {
                    dispatcher.forward(ctx.getRequest(), ctx.getResponse());
                    ctx.getResponse().flushBuffer();
                }
            }
        } catch (Exception var4) {
            ReflectionUtils.rethrowRuntimeException(var4);
        }

        return null;
    }

3.post類型過濾器

SendResponseFilter:將Zuul所代理的微服務的響應寫入當前響應

4.error類型過濾器

SendErrorFilter: 如果RequestContext.getThrowable()不為null,那么默認就會轉(zhuǎn)發(fā)到/error,也可以設(shè)置error.path屬性修改默認的轉(zhuǎn)發(fā)路徑。

五、@EnableZuulProxy注解

一、pre類型過濾器

PreDecorationFilter:該過濾器根據(jù)提供的RouteLocator確定路由到的地址,以及怎樣去路由。該路由器也可為后端請求設(shè)置各種代理相關(guān)的header。

二、route類型過濾器

(1) RibbonRoutingFilter:該過濾器使用Ribbon,Hystrix和可插拔的HTTP客戶端發(fā)送請求。serviceId在RequestContext.getCurrentContext().get("serviceId")中。該過濾器可使用不同的HTTP客戶端,例如:
  1.Apache HttpClient:默認的HTTP客戶端
  2.SquareupOkHttpClient v3:如需使用該客戶端,需保證com.squareup.okhttp3的依賴在classpath中,并設(shè)置如下:

 ribbon.okhttp.enabled = true

3.Netflix Ribbon HTTP client:設(shè)置如下即可啟用該HTTP客戶端。需要注意的是,該客戶端有一定限制,例如不支持PATCH方法,另外,它有內(nèi)置的重試機制。

 ribbon.restclient.enabled = true

(2) SimpleHostRoutingFilter:該過濾器通過Apache HttpClient向指定的URL發(fā)送請求。URL在RequestContext.getRouteHost()中。

六、使用zuul所遇到的問題

(1)注意zuul路由的請求路徑問題(按請求路由)

查看下面請求路由配置
# 在微服務中有個個record的子服務,需要將他的所有符合匹配規(guī)則的請求通過zuul轉(zhuǎn)發(fā)
# record 微服務部署ip 為192.168.1.126 端口為10007 
#  zuul 微服務部署ip 192.168.1.126 端口10009
zuul.routes.record-serve.path=/api/record-server/**
zuul.routes.record-serve.url=http://192.168.1.126:10007/

你在未使用zuul網(wǎng)關(guān)訪問的路徑是http://192.168.1.126:10007/api/record-server/hello,此時訪問 http://192.168.1.126:10009/api/record-server/hello,結(jié)果是404,由于你strpPrefix設(shè)置的是true,匹配訪問時是會忽略/api/record-server/段的,你正真匹配發(fā)送到record服務的請求是http://192.168.1.126:10007/hello,所以會導致404.
  那是由于zuul 默認設(shè)置的stripPrefix是ture,轉(zhuǎn)發(fā)時默認去掉請求前綴之后再進行轉(zhuǎn)發(fā)

zuul.routes.record-serve.path=/api/record-server/**
zuul.routes.record-serve.stripPrefix=false
zuul.routes.record-serve.url=http://192.168.1.126:10007/
通過查看zuul配置文件的部分源碼可以看到各項的默認值,
@ConfigurationProperties("zuul")
public class ZuulProperties {
    public static final List<String> SECURITY_HEADERS = Arrays.asList("Pragma", "Cache-Control", "X-Frame-Options", "X-Content-Type-Options", "X-XSS-Protection", "Expires");
    private String prefix = "";
    private boolean stripPrefix = true;
    private Boolean retryable = false;
    private boolean addProxyHeaders = true;
    private boolean addHostHeader = false;
    private boolean ignoreSecurityHeaders = true;
    private boolean forceOriginalQueryStringEncoding = false;
    private String servletPath = "/zuul";
    private boolean ignoreLocalService = true;
    private ZuulProperties.Host host = new ZuulProperties.Host();
    private boolean traceRequestBody = true;
    private boolean removeSemicolonContent = true;
    private Set<String> sensitiveHeaders = new LinkedHashSet(Arrays.asList("Cookie", "Set-Cookie", "Authorization"));
    private boolean sslHostnameValidationEnabled = true;
    private ExecutionIsolationStrategy ribbonIsolationStrategy;
    private ZuulProperties.HystrixSemaphore semaphore;

(2)zuul不能通過服務名稱路由的問題

第一,注意是否整合了eureka注冊中心和是否在設(shè)置項目啟動配置時使用的是@EnableZuulProxy和@EnableEurekaClient的組合,只有將zuul注冊到eureka中和使用EnableZuulServer的升級版EnableZuulProxy才能夠通過服務名稱找到對應的服務服務地址。
第二, 確認使用的是netfilix ribbon HttpClient client。如果沒有使用下面代碼配置開啟,如果沒有設(shè)置,zuul默認使用apache httpclient.

ribbon.restclient.enabled = true
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 張愛玲曾經(jīng)說過:“也許每一個男子全都有過這樣的兩個女人,至少兩個。娶了紅玫瑰,久而久之,紅的變了墻上的一抹蚊子血,...
    盤尼尼閱讀 968評論 0 1
  • 傳說中《 白夜行》的姐妹篇/續(xù)篇?私以為實在擔當不起,論人物的飽滿度、劇情的起伏轉(zhuǎn)承,都遠不及 白夜行 來得令人驚...
    佐佐吧閱讀 844評論 0 3
  • 終于在春節(jié)前一周抵達上海。這一次我們沒有回家里長輩住處,而是選擇入住了上海的airbnb。房子坐落在上海市中心,舊...
    江弘閱讀 475評論 0 2

友情鏈接更多精彩內(nèi)容