Spring Cloud網(wǎng)關(guān)服務(wù) - Zuul

快速入門

新建zuul-gateway工程藻丢,引入pom依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

引導(dǎo)類標(biāo)注

@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApplication.class, args);
    }

}

基于服務(wù)發(fā)現(xiàn)配置路由規(guī)則

zuul.routes.feign.path=/feign/**
zuul.routes.feign.service-id=feign-consumer

zuul.routes.hello.path=/hello/**
zuul.routes.hello.service-id=hello-service

請求過濾

實(shí)現(xiàn)ZuulFilter接口剪撬,如果請求內(nèi)容中沒有token,則返回401

@Slf4j
public class AccessFilter extends ZuulFilter {
    @Override
    public String filterType() {  //過濾器類型悠反,這里為pre残黑,標(biāo)識會在請求被路由之前執(zhí)行
        return "pre";
    }

    @Override
    public int filterOrder() { //過濾器的執(zhí)行順序
        return 0;
    }

    @Override
    public boolean shouldFilter() { //過濾是否會被執(zhí)行,在應(yīng)用中可以根據(jù)業(yè)務(wù)需求自定義實(shí)現(xiàn)
        return true;
    }

    @Override
    public Object run() throws ZuulException { //過濾器具體邏輯
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        log.info("filter..........");

        Object t = request.getParameter("token");
        if(Objects.isNull(t)) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}

注入filter實(shí)例

@Bean
ZuulFilter filter() {
    return new AccessFilter();
}

路由詳解

不依賴于服務(wù)治理斋否,單實(shí)例配置梨水,通過參數(shù)對配置

zuul.routes.<route>.path=/feign/**
zuul.routes.<route>.service-id=http://localhost:8080

多實(shí)例配置

zuul.routes.<route>.path=/feign/**
zuul.routes.<route>.service-id=MyService
#默認(rèn)依賴服務(wù)發(fā)現(xiàn)機(jī)制獲取服務(wù)名對應(yīng)的實(shí)例清單,沒有整合eureka茵臭,所以需要設(shè)置為false
ribbon.eureka.enabled=false 
MyService.ribbon.listOfServers=http://localhost:8080,http://localhost:8081

服務(wù)路由的默認(rèn)規(guī)則

在實(shí)際應(yīng)用中疫诽,大部分的路由配置幾乎都會采用服務(wù)名作為請求前綴,對于這種有規(guī)則的配置內(nèi)容旦委,在引入eureka后奇徒,zuul會自動創(chuàng)建一個默認(rèn)路由規(guī)則,這個默認(rèn)規(guī)則的path會使用serviceId作為請求前綴

在配置文件中注釋掉自定義路由規(guī)則

#zuul.routes.feign.path=/feign/**
#zuul.routes.feign.service-id=feign-consumer

直接使用serviceId作為請求前綴發(fā)起請求缨硝,也可以實(shí)現(xiàn)正常訪問

http://localhost:8084/<serviceId>/ask1?name=sdfsdf&token=sdfsdf

自定義路由規(guī)則

可以使用正則表達(dá)式自定義路由規(guī)則

@Bean
PatternServiceRouteMapper patternServiceRouteMapper() {
    return new PatternServiceRouteMapper("","");
}
  1. 參數(shù)一檢查服務(wù)名稱是否匹配正則表達(dá)式
  2. 參數(shù)二根據(jù)服務(wù)名定義的內(nèi)容轉(zhuǎn)換出的路徑表達(dá)式
路徑匹配

采用ant表達(dá)式風(fēng)格逼龟,即?//*,這里需要注意的是,路由的保存是有序的追葡,而通過properties文件加載是無序的,可以通過yaml文件來實(shí)現(xiàn)有序的路由規(guī)則

zuul:
    routes:
        feign:
            path: /feign/**
            service-id: feign-consumer
        hello:
            path: /hello/**
            service-id: hello-service

忽略表達(dá)式

通過ignored-patterns可以設(shè)置不希望被網(wǎng)關(guān)路由的url表達(dá)式

zuul.ignored-patterns=/**/hello/*

路由前綴

為網(wǎng)關(guān)路由規(guī)則增加/api前綴

zuul.prefix=/api

本地跳轉(zhuǎn)

zuul支持forward形式的服務(wù)端跳轉(zhuǎn)配置奕短,下面的配置實(shí)現(xiàn)了hello跳轉(zhuǎn)到網(wǎng)關(guān)/local/hello的功能

zuul.routes.hello.path=/hello/**
zuul.routes.hello.service-id=forward:/local

Cookie和頭信息

默認(rèn)情況下宜肉,zuul在請求路由時,會過濾掉http請求頭中的一些敏感信息翎碑,防止被傳遞到下游服務(wù)器谬返,如Cookie,Authorization,Set-Cookie日杈,但是如果使用了spring security遣铝,shrio等安全框架時,需要使用這些敏感信息莉擒,可以通過以下兩種方式進(jìn)行配置

全局配置

zuul.sensitive-headers=

指定路由配置

設(shè)置敏感頭為空

zuul.routes.<route>.sensitive-headers=

或開啟自定義敏感頭

zuul.routes.<route>.custom-sensitive-headers=true

在使用安全框架時酿炸,登錄成功后,會返回302涨冀,location指向的是具體的服務(wù)地址填硕,而不是網(wǎng)關(guān),可以設(shè)置

zuul.add-host-header=true

這樣,使得網(wǎng)關(guān)在進(jìn)行路由轉(zhuǎn)發(fā)錢設(shè)置Host頭信息扁眯,標(biāo)識最初的服務(wù)器請求地址

Hystrix和ribbon支持

在spring-cloud-starter-netflix-zuul中已經(jīng)引入了hystrix和ribbon支持,可以設(shè)置ribbon及hystrix的相關(guān)配置

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  <version>2.2.2.RELEASE</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
  <version>2.2.2.RELEASE</version>
  <scope>compile</scope>
</dependency>

過濾器詳解

zuul中過濾器是實(shí)現(xiàn)請求轉(zhuǎn)發(fā)最關(guān)鍵的核心部件壮莹,每一個進(jìn)入zuul的http請求都會經(jīng)過一些列的過濾器處理鏈得到請求響應(yīng)并返回給客戶端

zuul中實(shí)現(xiàn)的過濾器包含四個基本特征,過濾類型姻檀,執(zhí)行順序命满,執(zhí)行條件,具體操作绣版,實(shí)際上就是ZuulFilter中定義的四個抽象方法

public class AccessFilter extends ZuulFilter {
    @Override
    public String filterType() {  //過濾器類型胶台,這里為pre,標(biāo)識會在請求被路由之前執(zhí)行
        return "pre";
    }

    @Override
    public int filterOrder() { //過濾器的執(zhí)行順序
        return 0;
    }

    @Override
    public boolean shouldFilter() { //過濾是否會被執(zhí)行僵娃,在應(yīng)用中可以根據(jù)業(yè)務(wù)需求自定義實(shí)現(xiàn)
        return true;
    }

    @Override
    public Object run() throws ZuulException { //過濾器具體邏輯

    }
}

zuul中概作,過濾器類型的執(zhí)行順序為

pre(customer) -> routing -> post -> error

其中error只有在前序三種過濾器發(fā)生錯誤時才會執(zhí)行

核心過濾器

zuul中定義了一批核心過濾器位于org.springframework.cloud.netflix.zuul.filters包下

pre階段

  1. ServletDetectionFilter:用來檢查是通過spring的dispatcherServlet處理運(yùn)行的還是通過ZuulServlet來處理運(yùn)行的,它的檢測結(jié)果會保存到當(dāng)前請求上下文的isDispaterServletRequest參數(shù)中
  2. Servlet30WrapperFilter:執(zhí)行順序-2默怨,將原始的httpservletequest包裝成servelt30requestwrapper對象
  3. FormBodyWrapperFilter:執(zhí)行順序-1讯榕,僅對兩類請求生效,application/x-www-form-urlencoded和multipart/form-data匙睹,將該兩類請求包裝成FormBodyRequestWrapper
  4. DebugFilter:執(zhí)行順序1愚屁,根據(jù)zuul.debug.request和請求中的debug參數(shù)決定是否執(zhí)行過濾器中操作。具體操作則是把debugRouting和debugRequest參數(shù)設(shè)置為true痕檬,在同一個請求的不同生命周期中都可以訪問這兩個參數(shù)霎槐,當(dāng)環(huán)境出現(xiàn)問題時,可以通過參數(shù)請求方式激活debug分析信息
  5. PreDecorationFilter:執(zhí)行順序5梦谜,pre階段最后執(zhí)行的過濾器丘跌,為當(dāng)前請求設(shè)置做預(yù)處理

route過濾器

  1. RibbonRoutingFilter:執(zhí)行順序10,只對配置serviceId路由規(guī)則的請求生效唁桩,通過ribbon和hystrix來向服務(wù)實(shí)例發(fā)起請求
  2. SimpleHostRoutingFilter:執(zhí)行順序100闭树,只對配置url路由規(guī)則的請求生效
  3. SendForwardFilter:執(zhí)行順序500,處理路由配置中forward本地跳轉(zhuǎn)

post過濾器

  1. SendErrorFilter:執(zhí)行順序0荒澡,將請求上下文中的錯誤信息來組成一個forward到api網(wǎng)關(guān)/error錯誤端點(diǎn)產(chǎn)生錯誤響應(yīng)
  2. SendResponseFilter:執(zhí)行順序1000报辱,利用請求上下文組織需要發(fā)送會客戶端的響應(yīng)內(nèi)容
異常處理

使用errorfilter自定義異常處理,流轉(zhuǎn)到SendErrorFilter

@Slf4j
public class ErrorFilter extends ZuulFilter {
    @Override
    public String filterType() {  //過濾器類型单山,這里為pre碍现,標(biāo)識會在請求被路由之前執(zhí)行
        return "error";
    }

    @Override
    public int filterOrder() { //過濾器的執(zhí)行順序
        return 10;
    }

    @Override
    public boolean shouldFilter() { //過濾是否會被執(zhí)行,在應(yīng)用中可以根據(jù)業(yè)務(wù)需求自定義實(shí)現(xiàn)
        return true;
    }

    @Override
    public Object run() throws ZuulException { //過濾器具體邏輯
        RequestContext ctx = RequestContext.getCurrentContext();
        Throwable t = ctx.getThrowable();

        log.info("filter..........");
        
        ctx.set("error.status_code",HttpStatus.BAD_GATEWAY.value());
        ctx.set("error.exception",t.getCause());
        return null;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末米奸,一起剝皮案震驚了整個濱河市昼接,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悴晰,老刑警劉巖辩棒,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡一睁,警方通過查閱死者的電腦和手機(jī)钻弄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來者吁,“玉大人窘俺,你說我怎么就攤上這事「吹剩” “怎么了瘤泪?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長育八。 經(jīng)常有香客問我对途,道長,這世上最難降的妖魔是什么髓棋? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任实檀,我火速辦了婚禮,結(jié)果婚禮上按声,老公的妹妹穿的比我還像新娘膳犹。我一直安慰自己,他們只是感情好签则,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布须床。 她就那樣靜靜地躺著,像睡著了一般渐裂。 火紅的嫁衣襯著肌膚如雪豺旬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天柒凉,我揣著相機(jī)與錄音哈垢,去河邊找鬼。 笑死扛拨,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的举塔。 我是一名探鬼主播绑警,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼央渣!你這毒婦竟也來了计盒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤芽丹,失蹤者是張志新(化名)和其女友劉穎北启,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咕村,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年场钉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片懈涛。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡逛万,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出批钠,到底是詐尸還是另有隱情宇植,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布埋心,位于F島的核電站指郁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拷呆。R本人自食惡果不足惜闲坎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望洋腮。 院中可真熱鬧箫柳,春花似錦、人聲如沸啥供。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伙狐。三九已至涮毫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贷屎,已是汗流浹背罢防。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留唉侄,地道東北人咒吐。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像属划,于是被迫代替她去往敵國和親恬叹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355