<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring Cloud Gateway奪命連環(huán)10問(wèn)?

          共 12011字,需瀏覽 25分鐘

           ·

          2021-11-26 17:18

          ????關(guān)注后回復(fù)?“進(jìn)群”?,拉你進(jìn)程序員交流群????

          作者丨不才陳某

          來(lái)源丨碼猿技術(shù)專欄


          文章目錄如下:

          為什么需要網(wǎng)關(guān)?

          傳統(tǒng)的單體架構(gòu)中只有一個(gè)服務(wù)開(kāi)放給客戶端調(diào)用,但是微服務(wù)架構(gòu)中是將一個(gè)系統(tǒng)拆分成多個(gè)微服務(wù),那么作為客戶端如何去調(diào)用這些微服務(wù)呢?如果沒(méi)有網(wǎng)關(guān)的存在,只能在本地記錄每個(gè)微服務(wù)的調(diào)用地址。

          無(wú)網(wǎng)關(guān)的微服務(wù)架構(gòu)往往存在以下問(wèn)題:

          • 客戶端多次請(qǐng)求不同的微服務(wù),增加客戶端代碼或配置編寫(xiě)的復(fù)雜性。
          • 認(rèn)證復(fù)雜,每個(gè)服務(wù)都需要獨(dú)立認(rèn)證。
          • 存在跨域請(qǐng)求,在一定場(chǎng)景下處理相對(duì)復(fù)雜。

          網(wǎng)關(guān)的基本功能?

          網(wǎng)關(guān)是所有微服務(wù)的門(mén)戶,路由轉(zhuǎn)發(fā)僅僅是最基本的功能,除此之外還有其他的一些功能,比如:認(rèn)證鑒權(quán)熔斷限流日志監(jiān)控等等.........

          以上這些應(yīng)用場(chǎng)景會(huì)在后續(xù)的文章詳細(xì)介紹,不是今天的重點(diǎn)。

          為什么選擇Spring cloud Gateway?

          在1.x版本中都是采用的Zuul網(wǎng)關(guān);但在2.x版本中,zuul的升級(jí)一直跳票,Spring Cloud最后自己研發(fā)了一個(gè)網(wǎng)關(guān)替代Zuul,那就是Spring Cloud Gateway。

          肯定選擇親兒子Spring Cloud Gateway,它的很多思想都是借鑒zuul,所謂青出于藍(lán)而勝于藍(lán),功能和性能肯定是優(yōu)于zuul,不然Spring Cloud 為嘛要發(fā)布它?

          重要的一點(diǎn)原因:

          Spring Cloud Gateway 基于Spring Boot 2.x、Spring WebFlux和[Project Reactor構(gòu)建。

          對(duì)于Spring Boot 的整合方便兼容性以及性能方面不必?fù)?dān)心。

          Spring Cloud Gateway幾個(gè)必知的術(shù)語(yǔ)?

          1. 路由(route):gateway的基本構(gòu)建模塊。它由ID、目標(biāo)URI、斷言集合和過(guò)濾器集合組成。如果聚合斷言結(jié)果為真,則匹配到該路由。
          2. 斷言(Predicate ):參照J(rèn)ava8的新特性Predicate,允許開(kāi)發(fā)人員匹配HTTP請(qǐng)求中的任何內(nèi)容,比如頭或參數(shù)。
          3. 過(guò)濾器(filter):可以在返回請(qǐng)求之前或之后修改請(qǐng)求和響應(yīng)的內(nèi)容。

          網(wǎng)關(guān)如何搭建?

          為什么要放這張圖?

          一定要按照上圖中的版本進(jìn)行適配,否則會(huì)出現(xiàn)意想不到的BUG,陳某遇到過(guò),都是淚............

          新建cloud-gateway9023,添加如下依賴:


          <dependency>
          ????<groupId>org.springframework.cloudgroupId>
          ????<artifactId>spring-cloud-starter-gatewayartifactId>
          dependency>

          注意:一定要去掉spring-boot-starter-web依賴,否則啟動(dòng)報(bào)錯(cuò)

          好了,項(xiàng)目搭建完成,其實(shí)就添加這么一個(gè)依賴,關(guān)于詳細(xì)的配置下文介紹。

          什么是Predict(斷言)?

          Predicate來(lái)自于java8的接口。Predicate接受一個(gè)輸入?yún)?shù),返回一個(gè)布爾值結(jié)果。該接口包含多種默認(rèn)方法來(lái)將Predicate組合成其他復(fù)雜的邏輯(比如:與,或,非)。

          可以用于接口請(qǐng)求參數(shù)校驗(yàn)、判斷新老數(shù)據(jù)是否有變化需要進(jìn)行更新操作。

          Spring Cloud Gateway內(nèi)置了許多Predict,這些Predict的源碼在org.springframework.cloud.gateway.handler.predicate包中,有興趣可以閱讀一下。內(nèi)置的一些斷言如下圖:

          內(nèi)置的斷言

          以上11種斷言陳某這里就不再介紹如何配置了,官方文檔寫(xiě)的很清楚。

          官方文檔:https://docs.spring.io/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/

          下面就以最后一種權(quán)重?cái)嘌詾槔榻B一下如何配置。配置如下:

          spring:
          ??cloud:
          ????gateway:
          ??????##?路由
          ??????routes:
          ????????##?id只要唯一即可,名稱任意
          ????????-?id:?gateway-provider_1
          ??????????uri:?http://localhost:9024
          ??????????##?配置斷言
          ??????????predicates:
          ????????????##?Path?Route?Predicate?Factory斷言,滿足/gateway/provider/**這個(gè)請(qǐng)求路徑的都會(huì)被路由到http://localhost:9024這個(gè)uri中
          ????????????-?Path=/gateway/provider/**
          ????????????##?Weight?Route?Predicate?Factory,同一分組按照權(quán)重進(jìn)行分配流量,這里分配了80%
          ????????????##?第一個(gè)group1是分組名,第二個(gè)參數(shù)是權(quán)重
          ????????????-?Weight=group1,?8
          ????????????
          ????????##?id必須唯一
          ????????-?id:?gateway-provider_2
          ??????????##?路由轉(zhuǎn)發(fā)的uri
          ??????????uri:?http://localhost:9025
          ??????????##?配置斷言
          ??????????predicates:
          ????????????##?Path?Route?Predicate?Factory斷言,滿足/gateway/provider/**這個(gè)請(qǐng)求路徑的都會(huì)被路由到http://localhost:9024這個(gè)uri中
          ????????????-?Path=/gateway/provider/**
          ????????????##?Weight?Route?Predicate?Factory,同一分組按照權(quán)重進(jìn)行分配流量,這里分配了20%
          ????????????##?第一個(gè)group1是分組名,第二個(gè)參數(shù)是權(quán)重
          ????????????-?Weight=group1,?2

          routes下就是配置的路由策略,各個(gè)組件如下:

          • id:路由的唯一id,名稱任意
          • uri:路由轉(zhuǎn)發(fā)的uri
          • predicates:斷言配置,可以配置多個(gè)

          Spring Cloud Gateway中的斷言命名都是有規(guī)范的,格式:xxxRoutePredicateFactory

          比如權(quán)重的斷言:WeightRoutePredicateFactory,那么配置時(shí)直接取前面的Weight

          默認(rèn)的路由轉(zhuǎn)發(fā)如果路由到了兩個(gè),則是的按照配置先后順序轉(zhuǎn)發(fā),上面都配置了路徑:Path=/gateway/provider/**,如果沒(méi)有配置權(quán)重,則肯定是轉(zhuǎn)發(fā)到http://localhost:9024

          但是既然配置配置了權(quán)重并且相同的分組,則按照權(quán)重比例進(jìn)行分配流量。

          什么是過(guò)濾器?

          過(guò)濾器這個(gè)概念很熟悉,在Spring mvc 就接觸過(guò),Gateway的過(guò)濾器的作用以及生命周期都是類似的。

          Gateway的生命周期:

          • PRE:這種過(guò)濾器在請(qǐng)求被路由之前調(diào)用。我們可利用這種過(guò)濾器實(shí)現(xiàn)身份驗(yàn)證、在集群中選擇 請(qǐng)求的微服務(wù)、記錄調(diào)試信息等。
          • POST:這種過(guò)濾器在路由到微服務(wù)以后執(zhí)行。這種過(guò)濾器可用來(lái)為響應(yīng)添加標(biāo)準(zhǔn)的HTTP Header、收集統(tǒng)計(jì)信息和指標(biāo)、將響應(yīng)從微服務(wù)發(fā)送給客戶端等。

          Gateway 的Filter從作用范圍可分為兩種:

          • GatewayFilter:應(yīng)用到單個(gè)路由或者一個(gè)分組的路由上(需要在配置文件中配置)。
          • GlobalFilter:應(yīng)用到所有的路由上(無(wú)需配置,全局生效)

          GatewayFilter(局部過(guò)濾器)

          Spring Cloud Gateway中內(nèi)置了許多的局部過(guò)濾器,如下圖:

          局部過(guò)濾器需要在指定路由配置才能生效,默認(rèn)是不生效的。

          AddResponseHeaderGatewayFilterFactory這個(gè)過(guò)濾器為例,為原始響應(yīng)添加Header,配置如下:

          spring:
          ??cloud:
          ????gateway:
          ??????##?路由
          ??????routes:
          ????????##?id只要唯一即可,名稱任意
          ????????-?id:?gateway-provider_1
          ??????????uri:?http://localhost:9024
          ??????????##?配置斷言
          ??????????predicates:
          ????????????##?Path?Route?Predicate?Factory斷言,滿足/gateway/provider/**這個(gè)請(qǐng)求路徑的都會(huì)被路由到http://localhost:9024這個(gè)uri中
          ????????????-?Path=/gateway/provider/**
          ??????????##?配置過(guò)濾器(局部)
          ??????????filters:
          ????????????-?AddResponseHeader=X-Response-Foo,?Bar

          瀏覽器請(qǐng)求,發(fā)現(xiàn)響應(yīng)頭中已經(jīng)有了X-Response-Foo=Bar這個(gè)鍵值對(duì),如下圖:

          注意:過(guò)濾器的名稱只需要寫(xiě)前綴,過(guò)濾器命名必須是xxxGatewayFilterFactory(包括自定義)。

          更多過(guò)濾器的配置可以看官方文檔:https://docs.spring.io/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/#gatewayfilter-factories

          雖說(shuō)內(nèi)置的過(guò)濾器能夠解決很多場(chǎng)景,但是難免還是有些特殊需求需要定制一個(gè)過(guò)濾器,下面就來(lái)介紹一下如何自定義局部過(guò)濾器。

          場(chǎng)景:模擬一個(gè)授權(quán)驗(yàn)證的過(guò)程,如果請(qǐng)求頭或者請(qǐng)求參數(shù)中攜帶token則放行,否則直接攔截返回401,代碼如下:

          /**
          ?*?名稱必須是xxxGatewayFilterFactory形式
          ?*?todo:模擬授權(quán)的驗(yàn)證,具體邏輯根據(jù)業(yè)務(wù)完善
          ?*/

          @Component
          @Slf4j
          public?class?AuthorizeGatewayFilterFactory?extends?AbstractGatewayFilterFactory<AuthorizeGatewayFilterFactory.Config>?{

          ????private?static?final?String?AUTHORIZE_TOKEN?=?"token";

          ????//構(gòu)造函數(shù),加載Config
          ????public?AuthorizeGatewayFilterFactory()?{
          ????????//固定寫(xiě)法
          ????????super(AuthorizeGatewayFilterFactory.Config.class);
          ????????log.info("Loaded?GatewayFilterFactory?[Authorize]");
          ????}

          ????//讀取配置文件中的參數(shù)?賦值到?配置類中
          ????@Override
          ????public?List?shortcutFieldOrder()?{
          ????????//Config.enabled
          ????????return?Arrays.asList("enabled");
          ????}

          ????@Override
          ????public?GatewayFilter?apply(AuthorizeGatewayFilterFactory.Config?config)?{
          ????????return?(exchange,?chain)?->?{
          ????????????//判斷是否開(kāi)啟授權(quán)驗(yàn)證
          ????????????if?(!config.isEnabled())?{
          ????????????????return?chain.filter(exchange);
          ????????????}

          ????????????ServerHttpRequest?request?=?exchange.getRequest();
          ????????????HttpHeaders?headers?=?request.getHeaders();
          ????????????//從請(qǐng)求頭中獲取token
          ????????????String?token?=?headers.getFirst(AUTHORIZE_TOKEN);
          ????????????if?(token?==?null)?{
          ????????????????//從請(qǐng)求頭參數(shù)中獲取token
          ????????????????token?=?request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
          ????????????}

          ????????????ServerHttpResponse?response?=?exchange.getResponse();
          ????????????//如果token為空,直接返回401,未授權(quán)
          ????????????if?(StringUtils.isEmpty(token))?{
          ????????????????response.setStatusCode(HttpStatus.UNAUTHORIZED);
          ????????????????//處理完成,直接攔截,不再進(jìn)行下去
          ????????????????return?response.setComplete();
          ????????????}
          ????????????/**
          ?????????????*?todo?chain.filter(exchange)?之前的都是過(guò)濾器的前置處理
          ?????????????*
          ?????????????*?chain.filter().then(
          ?????????????*??過(guò)濾器的后置處理...........
          ?????????????*?)
          ?????????????*/

          ????????????//授權(quán)正常,繼續(xù)下一個(gè)過(guò)濾器鏈的調(diào)用
          ????????????return?chain.filter(exchange);
          ????????};
          ????}

          ????@Data
          ????@AllArgsConstructor
          ????@NoArgsConstructor
          ????public?static?class?Config?{
          ????????//?控制是否開(kāi)啟認(rèn)證
          ????????private?boolean?enabled;
          ????}
          }

          局部過(guò)濾器需要在路由中配置才能生效,配置如下:

          spring:
          ??cloud:
          ????gateway:
          ??????##?路由
          ??????routes:
          ????????##?id只要唯一即可,名稱任意
          ????????-?id:?gateway-provider_1
          ??????????uri:?http://localhost:9024
          ??????????##?配置斷言
          ??????????predicates:
          ????????????##?Path?Route?Predicate?Factory斷言,滿足/gateway/provider/**這個(gè)請(qǐng)求路徑的都會(huì)被路由到http://localhost:9024這個(gè)uri中
          ????????????-?Path=/gateway/provider/**
          ??????????##?配置過(guò)濾器(局部)
          ??????????filters:
          ????????????-?AddResponseHeader=X-Response-Foo,?Bar
          ????????????##?AuthorizeGatewayFilterFactory自定義過(guò)濾器配置,值為true需要驗(yàn)證授權(quán),false不需要
          ????????????-?Authorize=true

          此時(shí)直接訪問(wèn):http://localhost:9023/gateway/provider/port,不攜帶token,返回如下圖:

          請(qǐng)求參數(shù)帶上token:http://localhost:9023/gateway/provider/port?token=abcdcdecd-ddcdeicd12,成功返回,如下圖:

          上述的AuthorizeGatewayFilterFactory只是涉及到了過(guò)濾器的前置處理,后置處理是在chain.filter().then()中的then()方法中完成的,具體可以看下項(xiàng)目源碼中的TimeGatewayFilterFactory,代碼就不再貼出來(lái)了,如下圖:

          GlobalFilter(全局過(guò)濾器)

          全局過(guò)濾器應(yīng)用到全部路由上,無(wú)需開(kāi)發(fā)者配置,Spring Cloud Gateway也內(nèi)置了一些全局過(guò)濾器,如下圖:

          GlobalFilter的功能其實(shí)和GatewayFilter是相同的,只是GlobalFilter的作用域是所有的路由配置,而不是綁定在指定的路由配置上。多個(gè)GlobalFilter可以通過(guò)@Order或者getOrder()方法指定每個(gè)GlobalFilter的執(zhí)行順序,order值越小,GlobalFilter執(zhí)行的優(yōu)先級(jí)越高。

          注意,由于過(guò)濾器有pre和post兩種類型,pre類型過(guò)濾器如果order值越小,那么它就應(yīng)該在pre過(guò)濾器鏈的頂層,post類型過(guò)濾器如果order值越小,那么它就應(yīng)該在pre過(guò)濾器鏈的底層。示意圖如下:

          當(dāng)然除了內(nèi)置的全局過(guò)濾器,實(shí)際工作中還需要定制過(guò)濾器,下面來(lái)介紹一下如何自定義。

          場(chǎng)景:模擬Nginx的Access Log 功能,記錄每次請(qǐng)求的相關(guān)信息。代碼如下:

          /**
          ?*?實(shí)現(xiàn)GlobalFilter
          ?*/

          @Slf4j
          @Component
          @Order(value?=?Integer.MIN_VALUE)
          public?class?AccessLogGlobalFilter?implements?GlobalFilter?{

          ????@Override
          ????public?Mono?filter(ServerWebExchange?exchange,?GatewayFilterChain?chain)?{
          ????????//filter的前置處理
          ????????ServerHttpRequest?request?=?exchange.getRequest();
          ????????String?path?=?request.getPath().pathWithinApplication().value();
          ????????InetSocketAddress?remoteAddress?=?request.getRemoteAddress();
          ????????return?chain
          ????????????????//繼續(xù)調(diào)用filter
          ????????????????.filter(exchange)
          ????????????????//filter的后置處理
          ????????????????.then(Mono.fromRunnable(()?->?{
          ????????????ServerHttpResponse?response?=?exchange.getResponse();
          ????????????HttpStatus?statusCode?=?response.getStatusCode();
          ????????????log.info("請(qǐng)求路徑:{},遠(yuǎn)程IP地址:{},響應(yīng)碼:{}",?path,?remoteAddress,?statusCode);
          ????????}));
          ????}
          }

          好了,全局過(guò)濾器不必在路由上配置,注入到IOC容器中即可全局生效。

          此時(shí)發(fā)出一個(gè)請(qǐng)求,控制臺(tái)打印信息如下:

          請(qǐng)求路徑:/gateway/provider/port,遠(yuǎn)程IP地址:/0:0:0:0:0:0:0:1:64114,響應(yīng)碼:200?OK

          如何集成注冊(cè)中心?

          上述demo中并沒(méi)有集成注冊(cè)中心,每次路由配置都是指定固定的服務(wù)uri,如下圖:

          這樣做有什么壞處呢?

          • 服務(wù)的IP的地址一旦修改了,路由配置中的uri必須修改
          • 服務(wù)集群中無(wú)法實(shí)現(xiàn)負(fù)載均衡

          此時(shí)就需要集成的注冊(cè)中心,使得網(wǎng)關(guān)能夠從注冊(cè)中心自動(dòng)獲取uri(負(fù)載均衡)。

          這里的注冊(cè)中心當(dāng)然選擇Nacos,又不熟悉的小伙伴請(qǐng)看陳某《Spring Cloud 進(jìn)階》專欄的第一篇文章:五十五張圖告訴你微服務(wù)的靈魂擺渡者Nacos究竟有多強(qiáng)?

          pom文件中新增Nacos依賴,如下:


          ????<dependency>
          ??????<groupId>com.alibaba.cloudgroupId>
          ??????<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
          ????dependency>

          啟動(dòng)類上開(kāi)啟注冊(cè)中心功能,如下圖:

          配置文件中指定nacos注冊(cè)中心的地址:

          spring:
          ??application:
          ????##?指定服務(wù)名稱,在nacos中的名字
          ????name:?cloud-gateway
          ??cloud:
          ????nacos:
          ??????discovery:
          ????????#?nacos的服務(wù)地址,nacos-server中IP地址:端口號(hào)
          ????????server-addr:?127.0.0.1:8848

          路由配置中唯一不同的就是路由的uri,格式:lb://service-name,這是固定寫(xiě)法:

          • lb:固定格式,指的是從nacos中按照名稱獲取微服務(wù),并遵循負(fù)載均衡策略
          • service-name:nacos注冊(cè)中心的服務(wù)名稱,這里并不是IP地址形式的

          集成Nacos注冊(cè)中心完整的配置demo如下:

          spring:
          ??application:
          ????##?指定服務(wù)名稱,在nacos中的名字
          ????name:?cloud-gateway
          ??cloud:
          ????nacos:
          ??????discovery:
          ????????#?nacos的服務(wù)地址,nacos-server中IP地址:端口號(hào)
          ????????server-addr:?127.0.0.1:8848
          ????gateway:
          ??????##?路由
          ??????routes:
          ????????##?id只要唯一即可,名稱任意
          ????????-?id:?gateway-provider_1
          ????????##?使用了lb形式,從注冊(cè)中心負(fù)載均衡的獲取uri
          ??????????uri:?lb://gateway-provider
          ??????????##?配置斷言
          ??????????predicates:
          ????????????##?Path?Route?Predicate?Factory斷言,滿足/gateway/provider/**這個(gè)請(qǐng)求路徑的都會(huì)被路由到http://localhost:9024這個(gè)uri中
          ????????????-?Path=/gateway/provider/**
          ??????????##?配置過(guò)濾器(局部)
          ??????????filters:
          ????????????-?AddResponseHeader=X-Response-Foo,?Bar

          為什么指定了lb就可以開(kāi)啟負(fù)載均衡,前面說(shuō)過(guò)全局過(guò)濾器LoadBalancerClientFilter就是負(fù)責(zé)路由尋址和負(fù)載均衡的,可以看到如下源碼:

          如何實(shí)現(xiàn)動(dòng)態(tài)路由?

          上述例子都是將網(wǎng)關(guān)的一系列配置寫(xiě)到項(xiàng)目的配置文件中,一旦路由發(fā)生改變必須要重新項(xiàng)目,這樣維護(hù)成本很高。

          其實(shí)我們可以將網(wǎng)關(guān)的配置存放到配置中心中,這樣由配置中心統(tǒng)一管理,一旦路由發(fā)生改變,只需要在配置中心修改,這樣便能達(dá)到一處修改,多出生效的目的。

          這里當(dāng)然要使用Nacos作為配置中心了,添加依賴如下:


          ????<dependency>
          ??????<groupId>com.alibaba.cloudgroupId>
          ??????<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
          ????dependency>

          bootstrap.yml文件中指定Nacos作為配置中心的一些相關(guān)配置:

          spring:
          ??application:
          ????##?指定服務(wù)名稱,在nacos中的名字
          ????name:?cloud-gateway
          ??cloud:
          ????nacos:
          ??????##?todo?此處作為演示,僅僅配置了后綴,其他分組,命名空間根據(jù)需要自己配置
          ??????config:
          ????????server-addr:?127.0.0.1:8848
          ????????##?指定文件后綴未yaml
          ????????file-extension:?yaml

          在nacos中的public命名空間中創(chuàng)建dataIdcloud-gateway.yaml的配置(未指定環(huán)境),配置內(nèi)容如下:

          到這里已經(jīng)配置完成了。至于效果自己動(dòng)動(dòng)小手試試吧...............

          如何自定義全局異常處理?

          通過(guò)前面的測(cè)試可以看到一個(gè)現(xiàn)象:一旦路由的微服務(wù)下線或者失聯(lián)了,Spring Cloud Gateway直接返回了一個(gè)錯(cuò)誤頁(yè)面,如下圖:

          顯然這種異常信息不友好,前后端分離架構(gòu)中必須定制返回的異常信息。

          傳統(tǒng)的Spring Boot 服務(wù)中都是使用@ControllerAdvice來(lái)包裝全局異常處理的,但是由于服務(wù)下線,請(qǐng)求并沒(méi)有到達(dá)。

          因此必須在網(wǎng)關(guān)中也要定制一層全局異常處理,這樣才能更加友好的和客戶端交互。

          Spring Cloud Gateway提供了多種全局處理的方式,今天陳某只介紹其中一種方式,實(shí)現(xiàn)還算比較優(yōu)雅。

          直接創(chuàng)建一個(gè)類GlobalErrorExceptionHandler,實(shí)現(xiàn)ErrorWebExceptionHandler,重寫(xiě)其中的handle方法,代碼如下:

          /**
          ?*?用于網(wǎng)關(guān)的全局異常處理
          ?*?@Order(-1):優(yōu)先級(jí)一定要比ResponseStatusExceptionHandler低
          ?*/

          @Slf4j
          @Order(-1)
          @Component
          @RequiredArgsConstructor
          public?class?GlobalErrorExceptionHandler?implements?ErrorWebExceptionHandler?{

          ?private?final?ObjectMapper?objectMapper;

          ?@SuppressWarnings({"rawtypes",?"unchecked",?"NullableProblems"})
          ?@Override
          ?public?Mono?handle(ServerWebExchange?exchange,?Throwable?ex)?{
          ??ServerHttpResponse?response?=?exchange.getResponse();
          ??if?(response.isCommitted())?{
          ???return?Mono.error(ex);
          ??}

          ??//?JOSN格式返回
          ??response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
          ??if?(ex?instanceof?ResponseStatusException)?{
          ???response.setStatusCode(((ResponseStatusException)?ex).getStatus());
          ??}

          ??return?response.writeWith(Mono.fromSupplier(()?->?{
          ???DataBufferFactory?bufferFactory?=?response.bufferFactory();
          ???try?{
          ????//todo?返回響應(yīng)結(jié)果,根據(jù)業(yè)務(wù)需求,自己定制
          ????CommonResponse?resultMsg?=?new?CommonResponse("500",ex.getMessage(),null);
          ????return?bufferFactory.wrap(objectMapper.writeValueAsBytes(resultMsg));
          ???}
          ???catch?(JsonProcessingException?e)?{
          ????log.error("Error?writing?response",?ex);
          ????return?bufferFactory.wrap(new?byte[0]);
          ???}
          ??}));
          ?}
          }

          好了,全局異常處理已經(jīng)定制完成了,在測(cè)試一下,此時(shí)正常返回JSON數(shù)據(jù)了,如下圖:

          JSON的樣式根據(jù)架構(gòu)需要自己定制。

          總結(jié)

          Spring Cloud Gateway今天就分享到這里,主要介紹了以下幾個(gè)知識(shí)點(diǎn):

          • 為什么需要網(wǎng)關(guān)?網(wǎng)關(guān)的基本功能
          • 如何從零搭建一個(gè)微服務(wù)網(wǎng)關(guān)
          • Predict(斷言)的概念
          • 過(guò)濾器的概念、Spring Cloud Gateway內(nèi)置的過(guò)濾器以及如何自定義
          • 如何集成Nacos注冊(cè)中心并且實(shí)現(xiàn)負(fù)載均衡
          • 如何集成Nacos實(shí)現(xiàn)動(dòng)態(tài)路由,達(dá)到一處修改,多出生效的作用
          • 全局異常的處理

          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?面試題?資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來(lái),可以說(shuō)是程序員面試必備!所有資料都整理到網(wǎng)盤(pán)了,歡迎下載!

          點(diǎn)擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

          在看點(diǎn)這里好文分享給更多人↓↓

          瀏覽 24
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  求欧美精品网址 | 亚洲无码高清视频 | 国产草草| 日韩极品在线观看 | 精品婷婷一区二区三区四区五区 |