1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        SpringCloud系列之API網(wǎng)關(guān)(Gateway)服務(wù)Zuul

        共 12155字,需瀏覽 25分鐘

         ·

        2021-06-10 03:19

        走過(guò)路過(guò)不要錯(cuò)過(guò)

        點(diǎn)擊藍(lán)字關(guān)注我們


        1、什么是API網(wǎng)關(guān)

        API網(wǎng)關(guān)是所有請(qǐng)求的入口,承載了所有的流量,API Gateway是一個(gè)門戶一樣,也可以說(shuō)是進(jìn)入系統(tǒng)的唯一節(jié)點(diǎn)。這跟面向?qū)ο笤O(shè)計(jì)模式中的Facet模式很像。API Gateway封裝內(nèi)部系統(tǒng)的架構(gòu),并且提供API給各個(gè)客戶端。它還可能有其他功能,如授權(quán)、監(jiān)控、負(fù)載均衡、緩存、請(qǐng)求分片和管理、靜態(tài)響應(yīng)處理等

        API Gateway負(fù)責(zé)請(qǐng)求轉(zhuǎn)發(fā)、合成和協(xié)議轉(zhuǎn)換。所有來(lái)自客戶端的請(qǐng)求都要先經(jīng)過(guò)API Gateway,然后路由這些請(qǐng)求到對(duì)應(yīng)的微服務(wù)。API Gateway將經(jīng)常通過(guò)調(diào)用多個(gè)微服務(wù)來(lái)處理一個(gè)請(qǐng)求以及聚合多個(gè)服務(wù)的結(jié)果。它可以在web協(xié)議與內(nèi)部使用的非Web友好型協(xié)議間進(jìn)行轉(zhuǎn)換,如 HTTP協(xié)議、WebSocket協(xié)議。

        畫圖表示,沒(méi)有網(wǎng)關(guān)的情況,客戶端的請(qǐng)求會(huì)直接落到后端的各個(gè)服務(wù)中,無(wú)法集中統(tǒng)一管理。

        畫圖表示,有網(wǎng)關(guān)的情況,所有的請(qǐng)求都先經(jīng)過(guò)網(wǎng)關(guān),然后進(jìn)行分發(fā)到對(duì)應(yīng)服務(wù)

        2、API網(wǎng)關(guān)的重要性

        API網(wǎng)關(guān)在微服務(wù)項(xiàng)目中是很重要的,網(wǎng)關(guān)提供一個(gè)統(tǒng)一的管理,服務(wù)間的調(diào)度變得有序

        引用nginx官方的一篇優(yōu)質(zhì)博客,https://www.nginx.com/blog/building-microservices-using-an-api-gateway/,例子介紹了一個(gè)龐雜的電商系統(tǒng),按照微服務(wù)理論進(jìn)行設(shè)計(jì),有如下各種服務(wù):

        • 購(gòu)物車服務(wù):購(gòu)物車中的物品數(shù)量

        • 訂單服務(wù):訂單歷史記錄

        • 目錄服務(wù):基本產(chǎn)品信息,例如其名稱,圖像和價(jià)格

        • 審核服務(wù):客戶審核

        • 庫(kù)存服務(wù):庫(kù)存不足警告

        • 運(yùn)送服務(wù):運(yùn)送選項(xiàng),期限和費(fèi)用與運(yùn)送提供商的API分開提取

        • 推薦服務(wù):建議項(xiàng)目

        在不使用網(wǎng)關(guān)的情況,客戶端直接調(diào)用各服務(wù):

        理想情況,各服務(wù)調(diào)用是可以正常使用的,但是隨著業(yè)務(wù)拓展,服務(wù)之間的調(diào)用越來(lái)越復(fù)雜,到時(shí)候系統(tǒng)就會(huì)變成如圖:

        如果沒(méi)有一個(gè)統(tǒng)一的管理,肯定是不合理的,所以可以引入網(wǎng)關(guān),作為一個(gè)統(tǒng)一的門戶,如圖:

        3、API Gateway的作用

        ok,簡(jiǎn)單介紹網(wǎng)關(guān)之后,要說(shuō)說(shuō)網(wǎng)關(guān)的作用,在Spring cloud官網(wǎng)也有過(guò)歸納:

        當(dāng)然,我們可以自己挑幾個(gè)重要的介紹

        • 動(dòng)態(tài)路由
          網(wǎng)關(guān)可以做路由轉(zhuǎn)發(fā),假如服務(wù)信息變了,只要改網(wǎng)關(guān)配置既可,所以說(shuō)網(wǎng)關(guān)有動(dòng)態(tài)路由(Dynamic Routing)的作用,如圖:

        • 請(qǐng)求監(jiān)控
          請(qǐng)求監(jiān)控可以對(duì)整個(gè)系統(tǒng)的請(qǐng)求進(jìn)行監(jiān)控,詳細(xì)地記錄請(qǐng)求響應(yīng)日志,如圖,可以將日志丟到消息隊(duì)列,如果沒(méi)有使用網(wǎng)關(guān)的話,記錄請(qǐng)求信息需要在各個(gè)服務(wù)中去做

        • 認(rèn)證鑒權(quán)
          認(rèn)證鑒權(quán)可以對(duì)每一個(gè)訪問(wèn)請(qǐng)求做認(rèn)證,拒絕非法請(qǐng)求,保護(hù)后端的服務(wù),不需要每個(gè)服務(wù)都做鑒權(quán),在項(xiàng)目中經(jīng)常有加上OAuth2.0、JWT,Spring Security進(jìn)行權(quán)限校驗(yàn)

        • 壓力測(cè)試
          有網(wǎng)關(guān)的系統(tǒng),如果要要對(duì)某個(gè)服務(wù)進(jìn)行壓力測(cè)試,可以如圖所示,改下網(wǎng)關(guān)配置既可,測(cè)試請(qǐng)求路由到測(cè)試服務(wù),測(cè)試服務(wù)會(huì)有單獨(dú)的測(cè)試數(shù)據(jù)庫(kù),這樣測(cè)試的請(qǐng)求就不會(huì)影響到正式的服務(wù)和數(shù)據(jù)庫(kù)

        4、什么是Netflix Zuul?

        Netflix Zuul是Netflix公司的產(chǎn)品,是一款A(yù)PI網(wǎng)關(guān)中間件。Zuul是一個(gè)基于 JVM 路由和服務(wù)端的負(fù)載均衡器。提供了路由、監(jiān)控、彈性、安全等服務(wù)。Zuul 能夠與 Eureka、Ribbon、Hystrix 等組件配合使用,提供統(tǒng)一的API網(wǎng)關(guān)處理

        5、Netflix Zuul工作原理

        參考Zuul官網(wǎng)wiki,Zuul的核心如圖其實(shí)就是過(guò)濾器,zuul基于Servlet實(shí)現(xiàn)。當(dāng)一個(gè)請(qǐng)求進(jìn)來(lái)時(shí),會(huì)先進(jìn)入 pre 過(guò)濾器,在 pre 過(guò)濾器執(zhí)行完后,接著就到了 routing 過(guò)濾器中,開始路由到具體的服務(wù)中,錯(cuò)誤的情況會(huì)被錯(cuò)誤過(guò)濾器攔截

        • 過(guò)濾器類型:

          • 前置過(guò)濾器(PRE FILTER):在路由過(guò)濾器之前執(zhí)行。功能可以包括請(qǐng)求身份驗(yàn)證,選擇原始服務(wù)器以及記錄調(diào)試信息。

          • 路由過(guò)濾器(ROUTE FILTER):處理將請(qǐng)求路由到源的過(guò)程。這是使用Apache HttpClient或Netflix Ribbon構(gòu)建和發(fā)送原始HTTP請(qǐng)求的地方。

          • 后置過(guò)濾器(POST FILTER):在將請(qǐng)求路由過(guò)濾器之后執(zhí)行。功能可以包括向響應(yīng)中添加標(biāo)準(zhǔn)HTTP標(biāo)頭,收集統(tǒng)計(jì)信息和指標(biāo)以及將響應(yīng)從源流傳輸?shù)娇蛻舳恕?/span>

          • 錯(cuò)誤過(guò)濾器(ERR FILTER):在其他階段之一發(fā)生錯(cuò)誤時(shí)就會(huì)調(diào)用到錯(cuò)誤過(guò)濾

        6、Zuul實(shí)驗(yàn)環(huán)境準(zhǔn)備

        環(huán)境準(zhǔn)備:

        • JDK 1.8

        • SpringBoot2.2.3

        • SpringCloud(Hoxton.SR6)

        • Maven 3.2+

        • 開發(fā)工具

          • IntelliJ IDEA

          • smartGit

        創(chuàng)建一個(gè)SpringBoot Initialize項(xiàng)目,詳情可以參考我之前博客:SpringBoot系列之快速創(chuàng)建項(xiàng)目教程


        maven配置:

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

        本博客的是基于spring-cloud-starter-netflix-eureka-client進(jìn)行試驗(yàn),試驗(yàn)前要運(yùn)行eureka服務(wù)端,eureka服務(wù)提供者,代碼請(qǐng)參考上一章博客

        項(xiàng)目創(chuàng)建成功后,先在啟動(dòng)類加上@EnableZuulProxy

        import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
        @SpringBootApplication@EnableZuulProxypublic class SpringcloudZuulApplication {
        public static void main(String[] args) { SpringApplication.run(SpringcloudZuulApplication.class, args); }}

        7、eureka、zuul配置

        eureka客戶端配置:

        server:  port: 8082# 指定application name,這個(gè)是微服務(wù)注冊(cè)的serviceIdspring:  application:    name: zuul-api-gateway
        eureka: client: # 服務(wù)注冊(cè)中心url service-url: defaultZone: http://localhost:8761/eureka/ # 網(wǎng)關(guān)服務(wù)注冊(cè)、發(fā)現(xiàn)都開放,所以 register-with-eureka、fetch-registry都是true register-with-eureka: true fetch-registry: true instance: status-page-url-path: http://localhost:8761/actuator/info health-check-url-path: http://localhost:8761/actuator/health prefer-ip-address: true instance-id: zuul-api-gateway8082

        Zuul 配置路由規(guī)則:

        zuul:  routes:    provider: # 路由標(biāo)識(shí),可以自己定義      service-id: eureka-service-provider # 服務(wù)id(必須配置)      path: /provider/** # 映射的路徑,一般和routes.provider一致      url: http://localhost:8083 # 路由到的url,可以不配置

        Zuul配置訪問(wèn)前綴:訪問(wèn)時(shí)候需要加上前綴,eg:http://localhost:8082/api-gateway/provider/api/users/mojombo

        zuul:  # 配置前綴  prefix: /api-gateway

        Zuul配置Header過(guò)濾:

        zuul: # 配置過(guò)濾敏感的請(qǐng)求頭信息,設(shè)置為空就不會(huì)過(guò)濾  sensitive-headers: Cookie,Set-Cookie,Authorization

        Zuul配置重定向添加Host:

        zuul:# 重定向會(huì)添加host請(qǐng)求頭  add-proxy-headers: true

        Zuul超時(shí)設(shè)置:

        zuul:  host:    # 配置連接超時(shí)時(shí)間    connect-timeout-millis: 15000    # socker發(fā)送超時(shí)時(shí)間    socket-timeout-millis: 60000

        zuul所有配置參考,詳情參考官網(wǎng):

        zuul:  # 配置前綴  prefix: /api-gateway  routes:    provider: # 路由標(biāo)識(shí),可以自己定義      service-id: eureka-service-provider # 服務(wù)id      path: /provider/** # 映射的路徑,一般和routes.provider一致      url: http://localhost:8083 # 路由到的url  host:    # 配置連接超時(shí)時(shí)間    connect-timeout-millis: 15000    # socker發(fā)送超時(shí)時(shí)間    socket-timeout-millis: 60000  # 請(qǐng)求url編碼  decode-url: true  # 查詢字符串編碼  force-original-query-string-encoding: false  # 配置過(guò)濾敏感的請(qǐng)求頭信息,設(shè)置為空就不會(huì)過(guò)濾  sensitive-headers: Cookie,Set-Cookie,Authorization  # 重定向會(huì)添加host請(qǐng)求頭  add-proxy-headers: true

        訪問(wèn):http://localhost:8082/api-gateway/provider/api/users/mojombo,要加上前綴,配置的path

        可能遇到的錯(cuò)誤,504錯(cuò)誤:


        經(jīng)過(guò)排查,需要加上超時(shí)設(shè)置,因?yàn)檎{(diào)用服務(wù)超時(shí),導(dǎo)致504錯(cuò)誤

        zuul:  host:    connect-timeout-millis: 15000    socket-timeout-millis: 60000

        加上配置,調(diào)用服務(wù)成功

        8、Zuul自定義過(guò)濾器

        在前面的介紹中,已經(jīng)介紹了幾種過(guò)濾器,現(xiàn)在自定義實(shí)現(xiàn)這四種過(guò)濾器

        ps:spring cloud官網(wǎng)也提供了zuul過(guò)濾器的例子,詳情可以去github查看:https://github.com/spring-cloud-samples/sample-zuul-filters

        項(xiàng)目結(jié)構(gòu):


        過(guò)濾器類型參考o(jì)rg.springframework.cloud.netflix.zuul.filters.supportFilterConstants.java:

        實(shí)現(xiàn)一個(gè)前置過(guò)濾器:攔截請(qǐng)求,必須帶token過(guò)來(lái),不然拋出提示信息等等

        package com.example.springcloud.zuul.web.filter;
        import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import lombok.extern.slf4j.Slf4j;import org.apache.http.HttpHeaders;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;
        import javax.servlet.http.HttpServletRequest;
        import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.FORWARD_TO_KEY;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY;
        /** * <pre> * API網(wǎng)關(guān)預(yù)過(guò)濾器 * </pre> * * <pre> * @author mazq * 修改記錄 * 修改后版本: 修改人:修改日期: 2020/08/05 18:08 修改內(nèi)容: * </pre> */@Slf4j//@Componentpublic class ZuulApiGatewayPreFilter extends ZuulFilter {
        @Override public String filterType() { return PRE_TYPE; }
        @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 accessToken = request.getParameter("token"); if (StringUtils.isEmpty(accessToken)) { // zuul過(guò)濾該請(qǐng)求,不進(jìn)行路由 ctx.setSendZuulResponse(false); // 設(shè)置返回的錯(cuò)誤碼 ctx.setResponseStatusCode(403); ctx.setResponseBody("AccessToken is Invalid "); return null; } log.info("accessToken: {}",accessToken); // 否則業(yè)務(wù)繼續(xù)執(zhí)行 return null; }}

        后置過(guò)濾器,經(jīng)常被用于打印日志等等操作,代碼參考:https://www.baeldung.com/zuul-filter-modifying-response-body,實(shí)現(xiàn)效果時(shí),路由過(guò)濾器執(zhí)行之后,執(zhí)行后置過(guò)濾器打印日志:

        package com.example.springcloud.zuul.web.filter;
        import com.google.common.io.CharStreams;import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import lombok.extern.slf4j.Slf4j;import org.apache.http.protocol.RequestContent;import org.springframework.stereotype.Component;
        import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;
        import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE;import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
        /** * <pre> * API Gateway后置過(guò)濾器 * </pre> * * <pre> * @author mazq * 修改記錄 * 修改后版本: 修改人:修改日期: 2020/08/06 10:05 修改內(nèi)容: * </pre> */@Slf4j//@Componentpublic class ZuulApiGatewayPostFilter extends ZuulFilter { @Override public String filterType() { return POST_TYPE; }
        @Override public int filterOrder() { return 0; }
        @Override public boolean shouldFilter() { return true; }
        @Override public Object run() throws ZuulException { RequestContext context = RequestContext.getCurrentContext(); try (final InputStream responseDataStream = context.getResponseDataStream()) { if(responseDataStream == null) { log.warn("RESPONSE BODY: {}", ""); return null; } String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8")); log.info("RESPONSE BODY: {}", responseData); context.setResponseBody(responseData); } catch (Exception e) { throw new ZuulException(e, INTERNAL_SERVER_ERROR.value(), e.getMessage()); } return null; }}

        注冊(cè)過(guò)濾器,將過(guò)濾器加載到Spring容器,也可以在過(guò)濾器類加上@Component

        package com.example.springcloud.zuul;
        import com.example.springcloud.zuul.web.filter.ZuulApiGatewayErrFilter;import com.example.springcloud.zuul.web.filter.ZuulApiGatewayPostFilter;import com.example.springcloud.zuul.web.filter.ZuulApiGatewayPreFilter;import com.example.springcloud.zuul.web.filter.ZuulApiGatewayRouteFilter;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.zuul.EnableZuulProxy;import org.springframework.context.annotation.Bean;
        @SpringBootApplication@EnableZuulProxypublic class SpringcloudZuulApplication {
        public static void main(String[] args) { SpringApplication.run(SpringcloudZuulApplication.class, args); }
        @Bean public ZuulApiGatewayPreFilter zuulApiGatewayPreFilter(){ return new ZuulApiGatewayPreFilter(); } @Bean public ZuulApiGatewayPostFilter zuulApiGatewayPostFilter(){ return new ZuulApiGatewayPostFilter(); } @Bean public ZuulApiGatewayRouteFilter zuulApiGatewayRouteFilter(){ return new ZuulApiGatewayRouteFilter(); } @Bean public ZuulApiGatewayErrFilter zuulApiGatewayErrFilter(){ return new ZuulApiGatewayErrFilter(); }}

        訪問(wèn)網(wǎng)關(guān):http://localhost:8082/api-gateway/provider/api/users/mojombo,不帶token的情況


        http://localhost:8082/api-gateway/provider/api/users/mojombo?token=?,帶上token調(diào)用成功

        9、查看Zuul路由信息

        加上spring-boot-starter-actuator,進(jìn)行路由信息監(jiān)控:

        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-actuator</artifactId>        </dependency>

        spring-boot-starter-actuator配置:

        management:  endpoints:    web:      exposure:        # 默認(rèn)只支持info,health,開啟對(duì)routes的監(jiān)控        include: info,health,routes  # 開啟健康檢查詳細(xì)信息  endpoint:    health:      show-details: always

        查看路由詳細(xì),訪問(wèn)http://localhost:8082/actuator/routes,SpringBoot2.2.3版本要加上actuator前綴,調(diào)用成功,返回json數(shù)據(jù):

        {    "/api-gateway/provider/**":"eureka-service-provider",    "/api-gateway/eureka-service-provider/**":"eureka-service-provider"}

        查看路由詳細(xì)信息,訪問(wèn)鏈接:http://localhost:8082/actuator/routes/details

        {    "/api-gateway/provider/**":{        "id":"provider",        "fullPath":"/api-gateway/provider/**",        "location":"eureka-service-provider",        "path":"/**",        "prefix":"/api-gateway/provider",        "retryable":false,        "customSensitiveHeaders":false,        "prefixStripped":true    },    "/api-gateway/eureka-service-provider/**":{        "id":"eureka-service-provider",        "fullPath":"/api-gateway/eureka-service-provider/**",        "location":"eureka-service-provider",        "path":"/**",        "prefix":"/api-gateway/eureka-service-provider",        "retryable":false,        "customSensitiveHeaders":false,        "prefixStripped":true    }}

        本博客代碼例子下載:code download

        Zuul官網(wǎng)手冊(cè):
        spring Cloud官網(wǎng)zuul資料:https://docs.spring.io/spring-cloud-netflix/docs/2.2.x-SNAPSHOT/reference/html/#router-and-filter-zuul

        zuul github wiki:https://github.com/Netflix/zuul/wiki/How-it-Works

        github zuul過(guò)濾器例子:https://github.com/spring-cloud-samples/sample-zuul-filters



        往期精彩推薦



        騰訊、阿里、滴滴后臺(tái)面試題匯總總結(jié) — (含答案)

        面試:史上最全多線程面試題 !

        最新阿里內(nèi)推Java后端面試題

        JVM難學(xué)?那是因?yàn)槟銢](méi)認(rèn)真看完這篇文章


        END


        關(guān)注作者微信公眾號(hào) —《JAVA爛豬皮》


        了解更多java后端架構(gòu)知識(shí)以及最新面試寶典


        你點(diǎn)的每個(gè)好看,我都認(rèn)真當(dāng)成了


        看完本文記得給作者點(diǎn)贊+在看哦~~~大家的支持,是作者源源不斷出文的動(dòng)力


        作者:SmileNicky

        出處:https://www.cnblogs.com/mzq123/p/13447769.html

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

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲性爱小说 | 成人18禁秘 啪啪免费 | 天天综合网7799精品视频 | 他扯开我的奶罩一摸就流水 | 小泽玛利亚av在线 | 国产69精品久久久久毛片 | 三人交free性欧美zz0 一边吻一边摸双乳的电影 bdsm性折磨bdsm电击 | 操逼网络| 麻花传媒91mv在线观看 | 超碰毛片|