天天看點

spring cloud原理_SpringCloud學習筆記——舊服務網關Zuul原理入門執行個體Zuul原理——過濾器路由配置規則

spring cloud原理_SpringCloud學習筆記——舊服務網關Zuul原理入門執行個體Zuul原理——過濾器路由配置規則

入門執行個體

項目依賴

org.springframework.cloud            spring-cloud-starter-netflix-zuul                            org.springframework.cloud            spring-cloud-starter-netflix-eureka-client        
           

驅動網關工作

@[email protected](scanBasePackages ="com.spring.cloud.zuul.filter")public class DemoApplication {    public static void main(String[] args) {        SpringApplication.run(DemoApplication.class, args);    }}
           

在網關應用入口處使用@EnableZuulProxy注解驅動Zuul網關工作。

@EnableZuulProxy注解

@EnableCircuitBreaker//驅動Hystrix熔斷器工作@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Import({ZuulProxyMarkerConfiguration.class})public @interface EnableZuulProxy {}
           

之是以使用@EnableZuulProxy驅動Zuul網關工作後,需要驅動Hystrix熔斷器開啟工作,因為服務網關可以在高并發場景下請求流量過大時保護服務網關,使服務網關應用不至于癱瘓。預設情況下,Zuul會使用信号量隔離的方式使用Hystrix熔斷器,并非使用線程池的方式進行隔離。

網關配置

application.properties

# Zuul應用名稱spring.application.name=zuulDemo#Zuul應用端口server.port=8040#将服務網關應用注冊至服務注冊中心,并從服務注冊中心擷取服務執行個體清單(包含服務執行個體名稱,服務執行個體IP,服務執行個體端口号)eureka.client.service-url.defaultZone=http://server1:8701/eureka/,http://server2:8702/eureka/#配置通過path方式進行服務路由zuul.routes.user-router.path=/user/**#配置通過url方式進行服務路由zuul.routes.user-router.url=http://localhost:8100/#配置服務路由service-idzuul.router.user-router.service-id=user-service-provider
           

上述配置檔案中,zuul.routes.*用來配置路由資訊,本身是一個Map對象,後續的配置是為了配置路由資訊。zuul.routes.user-router.path用來配置使用者微服務比對路徑;zuul.routes.user-router.url用來配置使用者微服務實際路徑;如果使用者微服務存在多個服務執行個體,通過配置微服務執行個體Id的方式進行路由配置(zuul.router.user-router.service-id=服務執行個體Id)。

Zuul原理——過濾器

Zuul的本質是一套Servlet的API。其中ZuulServlet是核心Servlet,接收各類服務請求。此外,Zuul還提供了ZuulServletFilter攔截器,可以攔截各類請求。為了更加友善和快捷的增加和删除攔截邏輯,在ZuulServlet和ZuulServletFilter基礎上,定義了自己的過濾器ZuulFilter。

過濾器設計

ZuulFilter是一個抽象類,實作了接口IZuulFilter。Netflix Zuul提供了許多ZuulFilter實作類。在Spring Cloud Zuul中實作的過濾器必須包含4個特征:過濾類型、執行順序、執行條件、具體操作。在ZuulFilter抽象類中對4個過濾器特性進行了定義:

public abstract class ZuulFilter implements IZuulFilter, Comparable {    public abstract String filterType();    public abstract int filterOrder();    boolean shouldFilter();    Object run() throws ZuulException;}
           

方法的含義和功能總結如下:

方法名 描述
filterType 傳回過濾器類型字元串(pre,routing,post,error)
filterOrder 傳回該過濾器執行順序,數值越小執行順序越靠前
shouldFilter 傳回布爾值決定該過濾器是否需要執行
run 過濾器執行的具體邏輯,可在該方法中實作自定義的業務邏輯,傳回null則進行後續的正常邏輯

執行原理

在ZuulFilter抽象類中,定義的4個方法均沒有參數,如何執行過濾器相關操作?

過濾器攔截的均為Http請求,在Zuul中提供了以下核心類來完成過濾器相關工作。

核心類 描述
ZuulServlet 處理http請求入口,用于處理服務網關Http請求
ZuulRunner 用于對不同類型的過濾器進行串聯
FilterProcessor 執行具體的過濾器相關操作
RequestContext 請求上下文,用于擷取請求參數和設定響應資訊

RequestContext

每一個新的http請求都是由一個獨立的線程進行處理(tomcat線程),本次請求的所有參數均在一個獨立的線程中進行處理,故将每次的請求上下文存儲于ThreadLocal(線程本地變量,每次處理過程中存儲RequestContex執行個體副本,避免參數誤操作)中。在initialValue方法中,每個Http請求隻能執行個體化自己的請求上下文(RequestContext)執行個體。

public class RequestContext extends ConcurrentHashMap {    private static final Logger LOG = LoggerFactory.getLogger(RequestContext.class);    protected static Class extends RequestContext> contextClass = RequestContext.class;    private static RequestContext testContext = null;    protected static final ThreadLocal extends RequestContext> threadLocal = new ThreadLocal() {        protected RequestContext initialValue() {            try {                return (RequestContext)RequestContext.contextClass.newInstance();            } catch (Throwable var2) {                throw new RuntimeException(var2);            }        }    };    public static RequestContext getCurrentContext() {        if (testContext != null) {            return testContext;        } else {            RequestContext context = (RequestContext)threadLocal.get();            return context;        }    }    public boolean getBoolean(String key) {        return this.getBoolean(key, false);    }    public boolean getZuulEngineRan() {        return this.getBoolean("zuulEngineRan");    }    public void setZuulEngineRan() {        this.put("zuulEngineRan", true);    }    public HttpServletRequest getRequest() {        return (HttpServletRequest)this.get("request");    }    public void setRequest(HttpServletRequest request) {        this.put("request", request);    }    public HttpServletResponse getResponse() {        return (HttpServletResponse)this.get("response");    }    public void setResponse(HttpServletResponse response) {        this.set("response", response);    }    public void unset() {        threadLocal.remove();    }}
           
方法 描述
getCurrentContext 擷取目前請求上下文(RequestContext)
get(set)Request 擷取(設定)請求資訊
get(set)Response 擷取(設定)響應資訊 
get(set)ZuulEngineRan 設定Zuul引擎(ZuulRunner)
get(set)Boolean 擷取(設定)Boolean值
unset 從ThreadLocal中移除目前請求上下文副本

ZuulServlet

package com.netflix.zuul.http;public class ZuulServlet extends HttpServlet {    private static final long serialVersionUID = -3374242278843351500L;    private ZuulRunner zuulRunner;    public ZuulServlet() {    }    public void init(ServletConfig config) throws ServletException {        super.init(config);        //buffer-requests:初始化Zuul引擎(ZuulRunner)必要參數(預設為false)        String bufferReqsStr = config.getInitParameter("buffer-requests");        boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true");        this.zuulRunner = new ZuulRunner(bufferReqs);    }    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {        try {            //初始化Zuul引擎(ZuulRunner)            this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);            RequestContext context = RequestContext.getCurrentContext();            //設定buffer-requests參數為true            context.setZuulEngineRan();            try {                this.preRoute();            } catch (ZuulException var13) {                this.error(var13);                this.postRoute();                return;            }            try {                this.route();            } catch (ZuulException var12) {                this.error(var12);                this.postRoute();                return;            }            try {                this.postRoute();            } catch (ZuulException var11) {                this.error(var11);            }        } catch (Throwable var14) {            this.error(new ZuulException(var14, 500, "UNHANDLED_EXCEPTION_" + var14.getClass().getName()));        } finally {            RequestContext.getCurrentContext().unset();        }    }    void postRoute() throws ZuulException {        this.zuulRunner.postRoute();    }    void route() throws ZuulException {        this.zuulRunner.route();    }    void preRoute() throws ZuulException {        this.zuulRunner.preRoute();    }    void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {        this.zuulRunner.init(servletRequest, servletResponse);    }    void error(ZuulException e) {        RequestContext.getCurrentContext().setThrowable(e);        this.zuulRunner.error();    }}
           
方法 描述
init(ServletConfig) 初始化Zuul執行引擎(ZuulRunner)
init(HttpServletRequst,HttpServletResponse) 設定Zuul執行引擎(ZuulRunner)請求(request)響應(response)資訊和參數
service() 執行過濾器相關操作
preRoute() 使用Zuul執行引擎執行前置過濾器(過濾器類型為pre)
route() 使用Zuul執行引擎執行路由過濾器(過濾器類型為routing)
postRoute() 使用Zuul執行引擎執行Post過濾器(過濾器類型為post)
error() 使用Zuul執行引擎執行異常過濾器(過濾器類型為error)

通過service方法,我們可以獲知Zuul過濾器執行順序如下:

  • 前置(pre)、路由(route)、post類型過濾器執行過程中均未發生異常,執行順序為pre->route->post,error類型不執行
  • 前置(pre)類型過濾器執行過程中發生異常,執行順序為pre->error->post
  • 路由(route)類型過濾器執行過程中發生異常,執行順序為pre->route->error->post
  • post類型過濾器執行過程中發生異常,執行順序為pre->route->post->error

service方法執行的過程中一旦發生異常,将抛出的Throwable執行個體設定到目前執行請求上下文的Throwable屬性内。執行過程中無論是否有異常發生,從線程本地變量中移除請求上下文(ReqeustContext)副本。

ZuulRunner

public class ZuulRunner {    private boolean bufferRequests;    public ZuulRunner() {        this.bufferRequests = true;    }    public ZuulRunner(boolean bufferRequests) {        this.bufferRequests = bufferRequests;    }    public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {        RequestContext ctx = RequestContext.getCurrentContext();        if (this.bufferRequests) {            ctx.setRequest(new HttpServletRequestWrapper(servletRequest));        } else {            ctx.setRequest(servletRequest);        }        ctx.setResponse(new HttpServletResponseWrapper(servletResponse));    }    public void postRoute() throws ZuulException {        FilterProcessor.getInstance().postRoute();    }    public void route() throws ZuulException {        FilterProcessor.getInstance().route();    }    public void preRoute() throws ZuulException {        FilterProcessor.getInstance().preRoute();    }    public void error() {        FilterProcessor.getInstance().error();    }}
           
public class HttpServletResponseWrapper extends javax.servlet.http.HttpServletResponseWrapper {    private int status = 0;    public HttpServletResponseWrapper(HttpServletResponse response) {        super(response);    }    public void setStatus(int sc) {        this.status = sc;        super.setStatus(sc);    }    public void setStatus(int sc, String sm) {        this.status = sc;        super.setStatus(sc, sm);    }    public int getStatus() {        return this.status;    }}
           

ZuulRunner作為Zuul執行引擎,初始化時将請求上下文(ReqeustContext)中的響應屬性設定為HttpServletResponseWrapper執行個體,該執行個體主要通過status屬性設定http響應狀态碼。如果參數bufferRequests為true,将請求上下文中的請求屬性設定為HttpServletRequestWrapper執行個體,HttpServletRequestWrapper類主要用于把請求的表單參數和請求體緩存(設定)在對應的屬性中,無特殊要求傳遞bufferRequests預設值(false)。

方法 描述
init 初始化Zuul執行引擎
postRoute 使用FilterProcessor執行個體執行post類型過濾器
route 使用FilterProcessor執行個體執行路由(類型為route)過濾器
preRoute 使用FilterProcessor執行個體執行前置(類型為pre)過濾器
error 使用FilterProcessor執行個體執行錯誤(類型為error)過濾器

FilterProcessor

public class FilterProcessor {    static FilterProcessor INSTANCE = new FilterProcessor();    protected static final Logger logger = LoggerFactory.getLogger(FilterProcessor.class);    private FilterUsageNotifier usageNotifier = new FilterProcessor.BasicFilterUsageNotifier();    public FilterProcessor() {    }    public static FilterProcessor getInstance() {        return INSTANCE;    }    public static void setProcessor(FilterProcessor processor) {        INSTANCE = processor;    }    public void setFilterUsageNotifier(FilterUsageNotifier notifier) {        this.usageNotifier = notifier;    }    public void postRoute() throws ZuulException {        try {            this.runFilters("post");        } catch (ZuulException var2) {            throw var2;        } catch (Throwable var3) {            throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_POST_FILTER_" + var3.getClass().getName());        }    }    public void error() {        try {            this.runFilters("error");        } catch (Throwable var2) {            logger.error(var2.getMessage(), var2);        }    }    public void route() throws ZuulException {        try {            this.runFilters("route");        } catch (ZuulException var2) {            throw var2;        } catch (Throwable var3) {            throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_ROUTE_FILTER_" + var3.getClass().getName());        }    }    public void preRoute() throws ZuulException {        try {            this.runFilters("pre");        } catch (ZuulException var2) {            throw var2;        } catch (Throwable var3) {            throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + var3.getClass().getName());        }    }    public Object runFilters(String sType) throws Throwable {        if (RequestContext.getCurrentContext().debugRouting()) {            Debug.addRoutingDebug("Invoking {" + sType + "} type filters");        }        boolean bResult = false;        List list = FilterLoader.getInstance().getFiltersByType(sType);        if (list != null) {            for(int i = 0; i < list.size(); ++i) {                ZuulFilter zuulFilter = (ZuulFilter)list.get(i);                Object result = this.processZuulFilter(zuulFilter);                if (result != null && result instanceof Boolean) {                    bResult |= (Boolean)result;                }            }        }        return bResult;    }    public Object processZuulFilter(ZuulFilter filter) throws ZuulException {        RequestContext ctx = RequestContext.getCurrentContext();        boolean bDebug = ctx.debugRouting();        String metricPrefix = "zuul.filter-";        long execTime = 0L;        String filterName = "";        try {            long ltime = System.currentTimeMillis();            filterName = filter.getClass().getSimpleName();            RequestContext copy = null;            Object o = null;            Throwable t = null;            if (bDebug) {                Debug.addRoutingDebug("Filter " + filter.filterType() + " " + filter.filterOrder() + " " + filterName);                copy = ctx.copy();            }            ZuulFilterResult result = filter.runFilter();            ExecutionStatus s = result.getStatus();            execTime = System.currentTimeMillis() - ltime;            switch(s) {            case FAILED:                t = result.getException();                ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);                break;            case SUCCESS:                o = result.getResult();                ctx.addFilterExecutionSummary(filterName, ExecutionStatus.SUCCESS.name(), execTime);                if (bDebug) {                    Debug.addRoutingDebug("Filter {" + filterName + " TYPE:" + filter.filterType() + " ORDER:" + filter.filterOrder() + "} Execution time = " + execTime + "ms");                    Debug.compareContextState(filterName, copy);                }            }            if (t != null) {                throw t;            } else {                //計數器統計                this.usageNotifier.notify(filter, s);                return o;            }        } catch (Throwable var15) {            if (bDebug) {                Debug.addRoutingDebug("Running Filter failed " + filterName + " type:" + filter.filterType() + " order:" + filter.filterOrder() + " " + var15.getMessage());            }            //計數器統計            this.usageNotifier.notify(filter, ExecutionStatus.FAILED);            if (var15 instanceof ZuulException) {                throw (ZuulException)var15;            } else {                ZuulException ex = new ZuulException(var15, "Filter threw Exception", 500, filter.filterType() + ":" + filterName);                ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);                throw ex;            }        }    }}
           

在FilterProcessor類中,提供屬性usageNotifier(類型為FilterUsageNotifier接口),預設實作類為FilterProcessor靜态内部類BasicFilterUsageNotifier,該類實作接口FilterUsageNotifier的notify方法(方法參數為ZuulFilter和ExecutionStatus枚舉),ExecutionStatus(處理狀态)枚舉中主要提供如下可選值

public enum ExecutionStatus {    SUCCESS(1),    SKIPPED(-1),    DISABLED(-2),    FAILED(-3);    private int status;    private ExecutionStatus(int status) {        this.status = status;    }}
           
可選值 描述
SUCCESS(1) 該過濾器處理成功
SKIPPED(-1) 該過濾器跳過處理
DISABLED(-2) 該過濾器為禁用狀态
FAILED(-3) 該過濾器處理失敗

在FilterProcesser類中,主要通過runFilter方法(參數為過濾器類型字元串)和processZuulFilter(參數為ZuulFilter對象)對過濾器進行執行并傳回執行結果。runFilter方法中傳回值為布爾類型(過濾器執行成功或失敗),該傳回值無實際意義,執行成功或失敗都通過請求上下文(ReqeustContext).addFilterExecutionSummary(參數分别為過濾器名稱,執行狀态枚舉值,執行時間)對過濾器執行結果進行記錄。

方法 描述
postRoute 執行post類型過濾器(字首為post)
route 執行路由類型過濾器(字首為route)
preRoute 執行前置類型過濾器(字首為pre)
error 執行錯誤類型過濾器(字首為error)
runFilter 通過參數擷取需要執行的過濾器類型,傳回執行結果
processZuulFilter 對具體的過濾器執行操作,并将執行結果設定在請求上下文(RequestContext)中

自動裝配的過濾器

過濾器類型 過濾器名 過濾器描述 順序
pre ServletDetectionFilter 标記處理Servlet的類型 -3
Servlet30WrapperFilter 包裝HttpServletRequest請求 -2
FromBodyWrapperFilter 包裝請求體 -1
DebugFilter 标記調試狀态 1
PreDecorationFilter 處理請求上下文供後續使用 5
route RibbonRoutingFilter serviceId請求轉發 10
SimpleHostRoutingFilter url請求轉發 100
SendForwardFilter forward請求轉發 500
post SendErrorFilter 處理有錯誤的請求響應
SendResponseFilter 處理正常處理的請求響應 1000

開發過濾器

在本例中,我們将通過過濾器對http請求過程中的使用者名、密碼、token參數資訊進行校驗,校驗成功通過過濾器為響應資訊設定新的響應頭(response-header)資訊。

使用者名校驗過濾器(UserNameFilter)

import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;import org.springframework.http.HttpStatus;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;/** * 根據使用者名進行校驗 */@Componentpublic class UserNameFilter extends ZuulFilter {    @Override   //設定過濾器類型    public String filterType() {        return FilterConstants.PRE_TYPE;    }    //使用者名校驗最先執行    @Override    public int filterOrder() {        return FilterConstants.SERVLET_DETECTION_FILTER_ORDER-3;    }    @Override    public boolean shouldFilter() {        return true;    }    //執行具體的校驗邏輯    @Override    public Object run() throws ZuulException {        RequestContext requestContext=RequestContext.getCurrentContext();        HttpServletRequest request=requestContext.getRequest();        if(null!=request.getParameter("userName"))        {            requestContext.setSendZuulResponse(true);            requestContext.setResponseStatusCode(200);            requestContext.set("isSuccess",true);        }        else{            requestContext.setSendZuulResponse(false);        throw new ZuulRuntimeException(new ZuulException(this.filterType()+":"+this.getClass().getSimpleName(), HttpStatus.UNAUTHORIZED.value(),"使用者名不能為空"));        }        return null;    }}
           

使用者密碼校驗(PassWordFilter)

import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;import org.springframework.http.HttpStatus;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;@Componentpublic class PassWordFilter extends ZuulFilter {    //設定過濾器類型    @Override    public String filterType() {        return FilterConstants.PRE_TYPE;    }    //設定過濾器執行順序    @Override    public int filterOrder() {        return FilterConstants.SERVLET_DETECTION_FILTER_ORDER-2;    }    @Override    public boolean shouldFilter() {        return true;    }    //執行具體的校驗邏輯    @Override    public Object run() throws ZuulException {        RequestContext requestContext=RequestContext.getCurrentContext();        HttpServletRequest request=requestContext.getRequest();        if(null!=request.getParameter("passWord"))        {            requestContext.setSendZuulResponse(true);            requestContext.setResponseStatusCode(200);            requestContext.set("isSuccess",true);        }        else        {            requestContext.setSendZuulResponse(false);            throw new ZuulRuntimeException(new ZuulException(this.filterType()+":"+this.getClass().getSimpleName(), HttpStatus.UNAUTHORIZED.value(),"密碼不能為空"));        }        return null;    }}
           

Token校驗器(AccessTokenFilter)

import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;import org.springframework.http.HttpStatus;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;@Componentpublic class AccessTokenFilter extends ZuulFilter {    @Override    public String filterType() {        return FilterConstants.PRE_TYPE;    }    @Override    public int filterOrder() {        return FilterConstants.SERVLET_DETECTION_FILTER_ORDER-1;    }    @Override    public boolean shouldFilter() {        return true;    }    @Override    public Object run() throws ZuulException {        RequestContext requestContext=RequestContext.getCurrentContext();        HttpServletRequest request=requestContext.getRequest();        if(null!=request.getParameter("accessToken"))        {            requestContext.setResponseStatusCode(200);            requestContext.setSendZuulResponse(true);            requestContext.set("isSuccess",true);        }        else{            requestContext.setSendZuulResponse(false);            throw new ZuulRuntimeException(new ZuulException(this.filterType()+":"+this.getClass().getSimpleName(), HttpStatus.UNAUTHORIZED.value(),"token不能為空"));        }        return null;    }}
           

設定響應頭過濾器(ResponseHeaderFilter)

import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletResponse;@Componentpublic class ResponseHeaderFilter extends ZuulFilter {    @Override    public String filterType() {        return FilterConstants.POST_TYPE;    }    @Override    public int filterOrder() {        return FilterConstants.SEND_RESPONSE_FILTER_ORDER-1;    }    @Override    public boolean shouldFilter() {        return true;    }    @Override    public Object run() throws ZuulException {        RequestContext requestContext=RequestContext.getCurrentContext();        HttpServletResponse response=requestContext.getResponse();        response.addHeader("response-header","response-header");        return null;    }}
           

使用者名、密碼、token資訊參數均在前置類型過濾器,在ServletDetectionFilter前執行校驗操作,校驗通過後交由Zuul内置過濾器在前置類型過濾器進行處理。前置類型過濾器處理完成,通過路由類型過濾器路由到post過濾器,設定響應頭過濾器為post類型過濾器,在正常處理響應請求(SendResponseFilter)前執行。

路由配置規則

預設路由通路規則

http://服務網關應用名稱:服務網關應用端口/服務提供者執行個體名稱
           

自定義通路URL

zuul.routes.服務執行個體ID=URL
           

如zuul.routes.user-service=/user/**就會将user-service微服務映射到/user/**通路路徑。

忽略指定微服務

zuul.ignored-services=服務提供者執行個體名稱
           

通過上述配置,可以配置需要忽略的服務執行個體,多個服務執行個體間用逗号(,)間隔

忽略所有微服務,隻路由指定微服務

zuul.ignored-services=*zuul.routes.user-service=/user/**
           

通過上述配置,可以配置忽略所有服務執行個體,隻路由到user-service執行個體

定義服務執行個體ID和對應路徑

zuul.routes.user-router.service-id=user-service-providerzuul.routes.user-router.path=/user/**
           

通過上述配置,同時指定使用者微服務執行個體ID為user-service-provider,對應路徑為/user/**,user-router隻是給路由一個有意義的名稱,可以任意起名。

同時指定path和URL

zuul.routes.user-route.url=http://localhost:8100/user-servicezuul.routes.user-route.path=/user/**
           

通過上述配置,可以将通路位址為/user/**的路由到使用者服務執行個體(localhost:8100為服務注冊中心位址,user-service為服務提供者配置的服務執行個體名稱)。

使用上述配置方式,不會使HystrixCommand執行,也不會使Ribbon負載均衡多個URL,破壞了Zuul的服務熔斷和負載均衡特性。

同時指定path和URL并且不破壞服務熔斷(Hystrix)負載均衡(Ribbon)特性

zuul.routes.user-route.service-id=user-service-providerzuul.routes.user-route.path=/user/**ribbon.eureka.enabled=false #為Ribbon禁用Eurekauser-service-provider.ribbon.listOfServers=localhost:8100,localhost:8101
           

通過上述配置,即可以指定path和URL,又保證Zuul的服務熔斷和負載均衡特性可用。配置負載均衡的服務執行個體名須與服務執行個體ID(service-id)配置内容一緻。

路由字首

zuul.prefix=/apizuul.routes.user-router=/user/**#zuul.routes.user-router.strip-prefix=true#zuul.strip-prefix=false
           

通過上述配置,路由轉發至使用者微服務執行個體時去掉/api字首;如果需要路由轉發時帶上路由字首,通過zuul.routes.user-service-provider.strip-prefix=true進行指定路由移除代理前置配置即可(user-router隻是為服務路由起了一個有意義的名字,可以任意起名),也可以通過zuul.strip-prefix=false對所有服務路由。

忽略某些路徑

在前面的路由配置規則中,提到了如何忽略微服務,有時我們還需要更細粒度的路由控制,例如想讓zuul路由到使用者微服務執行個體,又想保護使用者微服務的使用者角色配置相關服務不被通路,可以進行如下配置:

zuul.ignoredPatterns:/**/RoleConfig/**zuul.routes.user-service-provider=/user/**
           

通過上述配置,可以講使用者微服務路由到/userRoleConfig/**)。

本地轉發

在Zuul實作的API網關路由功能中,還支援forward形式的服務端轉發配置。通過配置path和url相關資訊就能夠實作本地轉發。

zuul.routes.user-route.url=http://localhost:8100/zuul.routes.user-route.path=/user/**zuul.routes.order-route.url=forward:/order-servicezuul.routes.user-route.path=/order/**
           

上述配置中,/user/**請求被轉發到http://localhost:8100/,/order/**請求被轉發到/order-service進行處理。在配置本地轉發後,需要在服務提供者應用中提供請求路徑為/order-service對應的接口進行服務調用處理,否則會因為本地轉發無法找到對應處理接口而傳回404錯誤。

繼續閱讀