黄色网址大全免费-黄色网址你懂得-黄色网址你懂的-黄色网址有那些-免费超爽视频-免费大片黄国产在线观看

Spring Cloud微服務(wù)實踐

Spring Cloud API網(wǎng)關(guān)Zuul

Spring Cloud的Zuul是什么

通過前面內(nèi)容的學(xué)習(xí),我們已經(jīng)可以基本搭建出一套簡略版的微服務(wù)架構(gòu)了,我們有注冊中心 Eureka,可以將服務(wù)注冊到該注冊中心中,我們有 Ribbon 或Feign 可以實現(xiàn)對服務(wù)負(fù)載均衡地調(diào)用,我們有 Hystrix 可以實現(xiàn)服務(wù)的熔斷,但是我們還缺少什么呢?

我們首先來看一個微服務(wù)架構(gòu)圖:

在上面的架構(gòu)圖中,我們的服務(wù)包括:內(nèi)部服務(wù) Service A 和內(nèi)部服務(wù) ServiceB,這兩個服務(wù)都是集群部署,每個服務(wù)部署了 3 個實例,他們都會通過 EurekaServer 注冊中心注冊與訂閱服務(wù),而 Open Service 是一個對外的服務(wù),也是集群部署,外部調(diào)用方通過負(fù)載均衡設(shè)備調(diào)用 Open Service 服務(wù),比如負(fù)載均衡使用 Nginx,這樣的實現(xiàn)是否合理,或者是否有更好的實現(xiàn)方式呢?接下來我們主要圍繞該問題展開討論。

1、如果我們的微服務(wù)中有很多個獨立服務(wù)都要對外提供服務(wù),那么我們要如何去管理這些接口?特別是當(dāng)項目非常龐大的情況下要如何管理?

2、在微服務(wù)中,一個獨立的系統(tǒng)被拆分成了很多個獨立的服務(wù),為了確保安全,權(quán)限管理也是一個不可回避的問題,如果在每一個服務(wù)上都添加上相同的權(quán)限驗證代碼來確保系統(tǒng)不被非法訪問,那么工作量也就太大了,而且維護(hù)也非常不方便。

為了解決上述問題,微服務(wù)架構(gòu)中提出了 API 網(wǎng)關(guān)的概念,它就像一個安檢站一樣,所有外部的請求都需要經(jīng)過它的調(diào)度與過濾,然后 API 網(wǎng)關(guān)來實現(xiàn)請求路由、負(fù)載均衡、權(quán)限驗證等功能;

那么 Spring Cloud 這個一站式的微服務(wù)開發(fā)框架基于 Netflix Zuul 實現(xiàn)了Spring Cloud Zuul,采用 Spring Cloud Zuul 即可實現(xiàn)一套 API 網(wǎng)關(guān)服務(wù)。

使用Zuul構(gòu)建API網(wǎng)關(guān)

1、創(chuàng)建一個普通的 Spring Boot 工程名為 06-springcloud-api-gateway,然后添加相關(guān)依賴,這里我們主要添加兩個依賴 zuul 和 eureka 依賴:

<!--添加spring cloud的zuul的起步依賴-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!--添加spring cloud的eureka的客戶端依賴-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2、在入口類上添加@EnableZuulProxy 注解,開啟 Zuul 的 API 網(wǎng)關(guān)服務(wù)功能:

@EnableZuulProxy //開啟Zuul的API網(wǎng)關(guān)服務(wù)功能
@SpringBootApplication
public class Application {
        public static void main(String[] args) {
           SpringApplication.run(Application.class, args);
        }
}

3、在 application.properties 文件中配置路由規(guī)則:

#配置服務(wù)內(nèi)嵌的Tomcat端口
server.port=8080

#配置服務(wù)的名稱
spring.application.name=06-springcloud-api-gateway 

#配置路由規(guī)則
zuul.routes.api-wkcto.path=/api-wkcto/** 
zuul.routes.api-wkcto.serviceId=05-springcloud-service-feign 

#配置API網(wǎng)關(guān)到注冊中心上,API網(wǎng)關(guān)也將作為一個服務(wù)注冊到eureka-server上
eureka.client.service-url.defaultZone=http://eureka8761:8761/eureka/,http:/
/eureka8762:8762/eureka/

以上配置,我們的路由規(guī)則就是匹配所有符合/api-wkcto/**的請求,只要路徑中帶有/api-wkcto/都將被轉(zhuǎn)發(fā)到 05-springcloud-service-feign 服務(wù)上,至于05-springcloud-service-feign 服務(wù)的地址到底是什么則由 eureka-server 注冊中心去分析,我們只需要寫上服務(wù)名即可。

以我們目前搭建的項目為例,請求 http://localhost:8080/api-wkcto/web/hello 接口則相當(dāng)于請求 http://localhost:8082/web/hello(05-springcloud-service-feign 服務(wù)的地址為 http://localhost:8082/web/hello),路由規(guī)則中配置的 api-wkcto 是路由的名字,可以任意定義,但是一組 path 和serviceId 映射關(guān)系的路由名要相同。

如果以上測試成功,則表示們的 API 網(wǎng)關(guān)服務(wù)已經(jīng)構(gòu)建成功了,我們發(fā)送的符合路由規(guī)則的請求將自動被轉(zhuǎn)發(fā)到相應(yīng)的服務(wù)上去處理。

Zuul進(jìn)行請求過濾

我們知道 Spring cloud Zuul 就像一個安檢站,所有請求都會經(jīng)過這個安檢站,所以我們可以在該安檢站內(nèi)實現(xiàn)對請求的過濾,下面我們以一個權(quán)限驗證案例說這一點:

1、我們定義一個過濾器類并繼承自 ZuulFilter,并將該 Filter 作為一個 Bean:

@Component 
public class AuthFilter extends ZuulFilter { 
    @Override 
    public String filterType() { 
        return "pre"; 
    } 
    @Override 
    public int filterOrder() { 
        return 0; 
    } 
    @Override 
    public boolean shouldFilter() { 
        return true; 
    } 
    @Override 
    public Object run() throws ZuulException { 
        RequestContext ctx = RequestContext.getCurrentContext(); 
        HttpServletRequest request = ctx.getRequest(); 
        String token = request.getParameter("token"); 
        if (token == null) { 
            ctx.setSendZuulResponse(false); 
            ctx.setResponseStatusCode(401); 
            
ctx.addZuulResponseHeader("content-type","text/html;charset=utf-8"); 
            ctx.setResponseBody("非法訪問"); 
        } 
        return null; 
    } 
} 

(1)filterType 方法的返回值為過濾器的類型,過濾器的類型決定了過濾器在哪個生命周期執(zhí)行,pre 表示在路由之前執(zhí)行過濾器,其他值還有 post、error、route 和 static,當(dāng)然也可以自定義。

(2)filterOrder 方法表示過濾器的執(zhí)行順序,當(dāng)過濾器很多時,我們可以通過該方法的返回值來指定過濾器的執(zhí)行順序。

(3)shouldFilter 方法用來判斷過濾器是否執(zhí)行,true 表示執(zhí)行,false 表示不執(zhí)行。

(4)run 方法則表示過濾的具體邏輯,如果請求地址中攜帶了 token 參數(shù)的話,則認(rèn)為是合法請求,否則為非法請求,如果是非法請求的話,首先設(shè)置ctx.setSendZuulResponse(false); 表示不對該請求進(jìn)行路由,然后設(shè)置響應(yīng)碼和響應(yīng)值。這個 run 方法的返回值目前暫時沒有任何意義,可以返回任意值。

2、通過 http://localhost:8080/api-wkcto/web/hello 地址訪問,就會被過濾器過濾。

Zuul的路由規(guī)則

1、 在前面的例子中:

#配置路由規(guī)則
zuul.routes.api-wkcto.path=/api-wkcto/**
zuul.routes.api-wkcto.serviceId=05-springcloud-service-feign

當(dāng)訪問地址符合/api-wkcto/**規(guī)則的時候,會被自動定位到05-springcloud-service-feign  服務(wù)上,不過兩行代碼有點麻煩,還可以簡化為:

zuul.routes.05-springcloud-service-feign=/api-wkcto/**
zuul.routes  后面跟著的是服務(wù)名,服務(wù)名后面跟著的是路徑規(guī)則,這種配置方式更簡單。

2、 如果映射規(guī)則我們什么都不寫,系統(tǒng)也給我們提供了一套默認(rèn)的配置規(guī)則默認(rèn)的配置規(guī)則如下:

#默認(rèn)的規(guī)則
zuul.routes.05-springcloud-service-feign.path=/05-springcloud-service-feign/**
zuul.routes.05-springcloud-service-feign.serviceId=05-springcloud-service-feign

3、默認(rèn)情況下,Eureka 上所有注冊的服務(wù)都會被 Zuul 創(chuàng)建映射關(guān)系來進(jìn)行路由。

但是對于我這里的例子來說,我希望:05-springcloud-service-feign 提供服務(wù);而01-springcloud-service-provider 作為服務(wù)提供者只對服務(wù)消費者提供服務(wù),不對外提供服務(wù)。

如果使用默認(rèn)的路由規(guī)則,則 Zuul 也會自動為01-springcloud-service-provider 創(chuàng)建映射規(guī)則,這個時候我們可以采用如下方式來讓 Zuul 跳過 01-springcloud-service-provider 服務(wù),不為其創(chuàng)建路由規(guī)則:

#忽略掉服務(wù)提供者的默認(rèn)規(guī)則
zuul.ignored-services=01-springcloud-service-provider

不給某個服務(wù)設(shè)置映射規(guī)則,這個配置我們可以進(jìn)一步細(xì)化,比如說我不想給/hello 接口路由,那我們可以按如下方式配置:

#忽略掉某一些接口路徑
zuul.ignored-patterns=/**/hello/**

此外,我們也可以統(tǒng)一的為路由規(guī)則增加前綴,設(shè)置方式如下:

#配置網(wǎng)關(guān)路由的前綴
zuul.prefix=/myapi

此時我們的訪問路徑就變成了 http://localhost:8080/myapi/web/hello

4、 路由規(guī)則通配符的含義:

通配符 含義 舉例 說明

?

匹配任意單個字符

/05-springcloud-service-feign/?

匹配

/05-springcloud-service-feign/a,

/05-springcloud-service-feign/b,

/05-springcloud-service-feign/c 等

*

匹配任意數(shù)量的字符

/05-springcloud-service-feign/*

匹配

/05-springcloud-service-feign/aaa,

/05-springcloud-service-feign/bbb,

/05-springcloud-service-feign/ccc 等,

無法匹配

/05-springcloud-service-feign/a/b/c

**

匹配任意數(shù)量的字符

/05-springcloud-service-feign/**

匹配

/05-springcloud-service-feign/aaa,

/05-springcloud-service-feign/bbb,

/05-springcloud-service-feign/ccc 等,

也可以匹配

/05-springcloud-service-feign/a/b/c

5、一般情況下 API 網(wǎng)關(guān)只是作為各個微服務(wù)的統(tǒng)一入口,但是有時候我們可能也需要在 API 網(wǎng)關(guān)服務(wù)上做一些特殊的業(yè)務(wù)邏輯處理,那么我們可以讓請求到達(dá) API 網(wǎng)關(guān)后,再轉(zhuǎn)發(fā)給自己本身,由 API 網(wǎng)關(guān)自己來處理,那么我們可以進(jìn)行如下的操作:

在 06-springcloud-api-gateway 項目中新建如下 Controller:

@RestController 
public class GateWayController { 
    @RequestMapping("/api/local") 
    public String hello() { 
        return "exec the api gateway."; 
    } 
} 

然后在 application.properties 文件中配置:

zuul.routes.gateway.path=/gateway/**
zuul.routes.gateway.url=forward:/api/local

Zuul的異常處理

Spring Cloud Zuul 對異常的處理是非常方便的,但是由于 Spring Cloud 處于迅速發(fā)展中,各個版本之間有所差異,本案例是以 Finchley.RELEASE 版本為例,來說明 Spring Cloud Zuul 中的異常處理問題。

首先我們來看一張官方給出的 Zuul 請求的生命周期圖:

1、正常情況下所有的請求都是按照 pre、route、post 的順序來執(zhí)行,然后由 post返回 response。

2、在 pre 階段,如果有自定義的過濾器則執(zhí)行自定義的過濾器。

3、pre、routing、post 的任意一個階段如果拋異常了,則執(zhí)行 error 過濾器。

我們可以有兩種方式統(tǒng)一處理異常:

(1)禁用 zuul 默認(rèn)的異常處理 SendErrorFilter 過濾器,然后自定義我們自己的Errorfilter 過濾器

zuul.SendErrorFilter.error.disable=true
@Component 
public class ErrorFilter extends ZuulFilter { 
    private static final Logger logger = 
LoggerFactory.getLogger(ErrorFilter.class); 
    @Override 
    public String filterType() { 
        return "error"; 
    } 
    @Override 
    public int filterOrder() { 
        return 1; 
    } 
    @Override 
    public boolean shouldFilter() { 
        return true; 
    } 
    @Override 
    public Object run() throws ZuulException { 
        try { 
            RequestContext context = RequestContext.getCurrentContext(); 
            ZuulException exception = (ZuulException)context.getThrowable(); 
            logger.error("進(jìn)入系統(tǒng)異常攔截", exception); 
            HttpServletResponse response = context.getResponse(); 
            response.setContentType("application/json; charset=utf8"); 
            response.setStatus(exception.nStatusCode); 
            PrintWriter writer = null; 
            try { 
                writer = response.getWriter(); 
                writer.print("{code:"+ exception.nStatusCode +",message:\""+ 
exception.getMessage() +"\"}"); 
            } catch (IOException e) { 
                e.printStackTrace(); 
            } finally { 
                if(writer!=null){ 
                    writer.close(); 
                } 
            } 
        } catch (Exception var5) { 
            ReflectionUtils.rethrowRuntimeException(var5); 
第  44頁共    52頁
蛙課網(wǎng)【動力節(jié)點旗下品牌】
http://www.wkcto.com

 
        } 
        return null; 
    } 
} 

(2)自定義全局 error  錯誤頁面

@RestController 
public class ErrorHandlerController implements ErrorController { 
    /** 
     * 出異常后進(jìn)入該方法,交由下面的方法處理
     */ 
    @Override 
    public String getErrorPath() { 
        return "/error"; 
    } 
    @RequestMapping("/error") 
    public Object error(){ 
        RequestContext ctx = RequestContext.getCurrentContext(); 
        ZuulException exception = (ZuulException)ctx.getThrowable(); 
        return exception.nStatusCode + "--" + exception.getMessage(); 
    } 
} 

 

全部教程
主站蜘蛛池模板: 永久福利盒子日韩日韩免费看 | 亚洲免费a | 500福利国产精品导航在线 | 一个人看www在线视频资源 | 欧美国产日韩一区 | 日韩最新网址 | 成年女人免费又黄又爽视频 | 日韩三级黄色 | 先锋影音在线资源669 | 成人性色生活片免费看成人性 | 黄色片一级视频 | 欧美一级色 | 好男人www社区资源在线观看 | 狠狠干天天爽 | 欧美一区二区另类有声小说 | 97国产在线观看 | 成人免费大片a毛片 | 日韩第一页在线观看 | 色综合天天综合 | 黄色福利影院 | 欧美午夜在线观看理论片 | 国产一级特黄全黄毛片 | 欧美日本高清视频在线观看 | 日本免费黄网 | 天天操精品视频 | 久久亚洲综合网 | 最好看2019高清中文字幕 | 国产精品亚洲欧美大片在线看 | 成人免费播放 | 欧美亚洲另类色国产综合 | 欧美有码在线观看 | 欧美亚洲国产一区 | 国产黄三级三·级三级 | 91精品一区二区三区在线 | 小明视频免费永久在线网 | 岛国在线最新 | 性放荡的三级小说 | 免费人成网555www | 欧美日韩不卡中文字幕在线 | 欧美中文综合在线视频 | 一级特黄a视频 |