0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何利用Gateway搭建網(wǎng)關(guān)服務(wù)?

jf_78858299 ? 來源:csdn ? 作者:?!な堑惯^來的天 ? 2023-01-21 16:06 ? 次閱讀

網(wǎng)關(guān)作為微服務(wù)中非常重要的一部分,是必須要掌握的;本文記錄一下我是如何使用Gateway搭建網(wǎng)關(guān)服務(wù)及實(shí)現(xiàn)動(dòng)態(tài)路由的,幫助大家學(xué)習(xí)如何快速搭建一個(gè)網(wǎng)關(guān)服務(wù),了解路由相關(guān)配置,鑒權(quán)的流程及業(yè)務(wù)處理,有興趣的一定看到最后,非常適合沒接觸過網(wǎng)關(guān)服務(wù)的同學(xué)當(dāng)作入門教程。

搭建服務(wù)

框架

SpringBoot 2.1

<parent>
   <groupId>org.springframework.bootgroupId>
   <artifactId>spring-boot-starter-parentartifactId>
   <version>2.1.0.RELEASEversion>
parent>

Spring-cloud-gateway-core

<dependency>
   <groupId>org.springframework.cloudgroupId>
   <artifactId>spring-cloud-gateway-coreartifactId>
dependency>

common-lang3

<dependency>
   <groupId>org.apache.commonsgroupId>
   <artifactId>commons-lang3artifactId>
dependency>

路由配置

網(wǎng)關(guān)作為請(qǐng)求統(tǒng)一入口,路由就相當(dāng)于是每個(gè)業(yè)務(wù)系統(tǒng)的入口,通過路由規(guī)則則可以匹配到對(duì)應(yīng)微服務(wù)的入口,將請(qǐng)求命中到對(duì)應(yīng)的業(yè)務(wù)系統(tǒng)中

server:
  port: 8080
 
spring:
  cloud:
    gateway:
      enabled: true
      routes:
      - id: demo-server
        uri: http://localhost:8081
        predicates:
        - Path=/demo-server/**
        filters:
          - StripPrefix= 1

routes

圖片

解讀配置

現(xiàn)在有一個(gè)服務(wù)demo-server部署在本機(jī),地址和端口127.0.0.1:8081,所以路由配置uri為http://localhost:8081

使用網(wǎng)關(guān)服務(wù)路由到此服務(wù),predicates -Path=/demo-server/**,網(wǎng)關(guān)服務(wù)的端口為8080,啟動(dòng)網(wǎng)關(guān)服務(wù),訪問localhost:8080/demo-server,路由斷言就會(huì)將請(qǐng)求路由到demo-server

直接訪問demo-server的接口localhost:8081/api/test,通過網(wǎng)關(guān)的訪問地址則為localhost:8080/demo-server/api/test,predicates配置將請(qǐng)求斷言到此路由,filters-StripPrefix=1代表將地址中/后的第一個(gè)截取,所以demo-server就截取掉了

使用gateway通過配置文件即可完成路由的配置,非常方便,我們只要充分的了解配置項(xiàng)的含義及規(guī)則就可以了;但是這些配置如果要修改則需要重啟服務(wù),重啟網(wǎng)關(guān)服務(wù)會(huì)導(dǎo)致整個(gè)系統(tǒng)不可用,這一點(diǎn)是無(wú)法接受的,下面介紹如何通過Nacos實(shí)現(xiàn)動(dòng)態(tài)路由

動(dòng)態(tài)路由

使用nacos結(jié)合gateway-server實(shí)現(xiàn)動(dòng)態(tài)路由,我們需要先部署一個(gè)nacos服務(wù),可以使用docker部署或下載源碼在本地啟動(dòng),具體操作可以參考官方文檔即可

Nacos配置
  • groupId: 使用網(wǎng)關(guān)服務(wù)名稱即可
  • dataId: routes
  • 配置格式:json
[{
      "id": "xxx-server",
      "order": 1, #優(yōu)先級(jí)
      "predicates": [{ #路由斷言
          "args": {
              "pattern": "/xxx-server/**"
          },
          "name": "Path"
      }],
      "filters":[{ #過濾規(guī)則
          "args": {
              "parts": 0 #k8s服務(wù)內(nèi)部訪問容器為http://xxx-server/xxx-server的話,配置0即可
          },
          "name": "StripPrefix" #截取的開始索引
      }],
      "uri": "http://localhost:8080/xxx-server" #目標(biāo)地址
  }]

json格式配置項(xiàng)與yaml中對(duì)應(yīng),需要了解配置在json中的寫法

比對(duì)一下json配置與yaml配置
{
    "id":"demo-server",
    "predicates":[
        {
            "args":{
                "pattern":"/demo-server/**"
            },
            "name":"Path"
        }
    ],
    "filters":[
        {
            "args":{
                "parts":1
            },
            "name":"StripPrefix"
        }
    ],
    "uri":"http://localhost:8081"
}
spring:
  cloud:
    gateway:
      enabled: true
      routes:
      - id: demo-server
        uri: http://localhost:8081
        predicates:
        - Path=/demo-server/**
        filters:
          - StripPrefix= 1
代碼實(shí)現(xiàn)

Nacos實(shí)現(xiàn)動(dòng)態(tài)路由的方式核心就是通過Nacos配置監(jiān)聽,配置發(fā)生改變后執(zhí)行網(wǎng)關(guān)相關(guān)api創(chuàng)建路由

圖片

@Component
public class NacosDynamicRouteService implements ApplicationEventPublisherAware {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(NacosDynamicRouteService.class);
 
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
 
    private ApplicationEventPublisher applicationEventPublisher;
 
    /** 路由id */
    private static List<String> routeIds = Lists.newArrayList();
 
    /**
     * 監(jiān)聽nacos路由配置,動(dòng)態(tài)改變路由
     * @param configInfo
     */
    @NacosConfigListener(dataId = "routes", groupId = "gateway-server")
    public void routeConfigListener(String configInfo) {
        clearRoute();
        try {
            List gatewayRouteDefinitions = JSON.parseArray(configInfo, RouteDefinition.class);
            for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {
                addRoute(routeDefinition);
            }
            publish();
            LOGGER.info("Dynamic Routing Publish Success");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } 
    }
    /**
     * 清空路由
     */
    private void clearRoute() {
        for (String id : routeIds) {
            routeDefinitionWriter.delete(Mono.just(id)).subscribe();
        }
        routeIds.clear();
    }
 
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
    /**
     * 添加路由
     * 
     * @param definition
     */
    private void addRoute(RouteDefinition definition) {
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            routeIds.add(definition.getId());
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }
    /**
     * 發(fā)布路由、使路由生效
     */
    private void publish() {
        this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
    }
}

過濾器

gateway提供GlobalFilter及Ordered兩個(gè)接口用來定義過濾器,我們自定義過濾器只需要實(shí)現(xiàn)這個(gè)兩個(gè)接口即可

  • GlobalFilter filter() 實(shí)現(xiàn)過濾器業(yè)務(wù)
  • Ordered getOrder() 定義過濾器執(zhí)行順序

通常一個(gè)網(wǎng)關(guān)服務(wù)的過濾主要包含 鑒權(quán)(是否登錄、是否黑名單、是否免登錄接口...) 限流(ip限流等等)功能,我們今天簡(jiǎn)單介紹鑒權(quán)過濾器的流程實(shí)現(xiàn)

鑒權(quán)過濾器

需要實(shí)現(xiàn)鑒權(quán)過濾器,我們先得了解登錄及鑒權(quán)流程,如下圖所示

由圖可知,我們鑒權(quán)過濾核心就是驗(yàn)證token是否有效,所以我們網(wǎng)關(guān)服務(wù)需要與業(yè)務(wù)系統(tǒng)在同一個(gè)redis庫(kù),先給網(wǎng)關(guān)添加redis依賴及配置

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-redis-reactiveartifactId>
dependency>
spring:
  redis:
    host: redis-server
    port: 6379
    password:
    database: 0

代碼實(shí)現(xiàn)

  1. 定義過濾器AuthFilter
  2. 獲取請(qǐng)求對(duì)象 從請(qǐng)求頭或參數(shù)或cookie中獲取token(支持多種方式傳token對(duì)于客戶端更加友好,比如部分web下載請(qǐng)求會(huì)新建一個(gè)頁(yè)面,在請(qǐng)求頭中傳token處理起來比較麻煩)
  3. 沒有token,返回401
  4. 有token,查詢r(jià)edis是否有效
  5. 無(wú)效則返回401,有效則完成驗(yàn)證放行
  6. 重置token過期時(shí)間、添加內(nèi)部請(qǐng)求頭信息方便業(yè)務(wù)系統(tǒng)權(quán)限處理
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    private static final String TOKEN_HEADER_KEY = "auth_token";
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.獲取請(qǐng)求對(duì)象
        ServerHttpRequest request = exchange.getRequest();
        // 2.獲取token
        String token = getToken(request);
        ServerHttpResponse response = exchange.getResponse();
        if (StringUtils.isBlank(token)) {
            // 3.token為空 返回401
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        // 4.驗(yàn)證token是否有效
        String userId = getUserIdByToken(token);
        if (StringUtils.isBlank(userId)) {
            // 5.token無(wú)效 返回401
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        // token有效,后續(xù)業(yè)務(wù)處理
        // 從寫請(qǐng)求頭,方便業(yè)務(wù)系統(tǒng)從請(qǐng)求頭獲取用戶id進(jìn)行權(quán)限相關(guān)處理
        ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
        request = builder.header("user_id", userId).build();
        // 延長(zhǎng)緩存過期時(shí)間-token緩存用戶如果一直在操作就會(huì)一直重置過期
        // 這樣避免用戶操作過程中突然過期影響業(yè)務(wù)操作及體驗(yàn),只有用戶操作間隔時(shí)間大于緩存過期時(shí)間才會(huì)過期
        resetTokenExpirationTime(token, userId);
        // 完成驗(yàn)證
        return chain.filter(exchange);
    }
 
    @Override
    public int getOrder() {
        // 優(yōu)先級(jí) 越小越優(yōu)先
        return 0;
    }
 
    /**
     * 從redis中獲取用戶id
     * 在登錄操作時(shí)候 登陸成功會(huì)生成一個(gè)token, redis得key為auth_token:token 值為用戶id
     *
     * @param token
     * @return
     */
    private String getUserIdByToken(String token) {
        String redisKey = String.join(":", "auth_token", token);
        return redisTemplate.opsForValue().get(redisKey);
    }
 
    /**
     * 重置token過期時(shí)間
     *
     * @param token
     * @param userId
     */
    private void resetTokenExpirationTime(String token, String userId) {
        String redisKey = String.join(":", "auth_token", token);
        redisTemplate.opsForValue().set(redisKey, userId, 2, TimeUnit.HOURS);
    }
 
    /**
     * 獲取token
     *
     * @param request
     * @return
     */
    private static String getToken(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        // 從請(qǐng)求頭獲取token
        String token = headers.getFirst(TOKEN_HEADER_KEY);
        if (StringUtils.isBlank(token)) {
            // 請(qǐng)求頭無(wú)token則從url獲取token
            token = request.getQueryParams().getFirst(TOKEN_HEADER_KEY);
        }
        if (StringUtils.isBlank(token)) {
            // 請(qǐng)求頭和url都沒有token則從cookies獲取
            HttpCookie cookie = request.getCookies().getFirst(TOKEN_HEADER_KEY);
            if (cookie != null) {
                token = cookie.getValue();
            }
        }
        return token;
    }
}

總結(jié)

Gateway通過配置項(xiàng)可以實(shí)現(xiàn)路由功能,整合Nacos及配置監(jiān)聽可以實(shí)現(xiàn)動(dòng)態(tài)路由,實(shí)現(xiàn)GlobalFilter,Ordered兩個(gè)接口可以快速實(shí)現(xiàn)一個(gè)過濾器,文中也詳細(xì)的介紹了登錄后的請(qǐng)求鑒權(quán)流程。

來源:https://blog.csdn.net/qq_31587111/article/details/122731977

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 網(wǎng)關(guān)
    +關(guān)注

    關(guān)注

    9

    文章

    4197

    瀏覽量

    50774
  • 路由
    +關(guān)注

    關(guān)注

    0

    文章

    274

    瀏覽量

    41706
  • Gateway
    +關(guān)注

    關(guān)注

    1

    文章

    16

    瀏覽量

    7876
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何使用Gateway搭建網(wǎng)關(guān)服務(wù)及實(shí)現(xiàn)動(dòng)態(tài)路由

    本文記錄一下我是如何使用Gateway搭建網(wǎng)關(guān)服務(wù)及實(shí)現(xiàn)動(dòng)態(tài)路由的,幫助大家學(xué)習(xí)如何快速搭建一個(gè)網(wǎng)關(guān)服務(wù)
    的頭像 發(fā)表于 09-23 15:15 ?1734次閱讀

    #硬聲創(chuàng)作季 14-JAVAEE實(shí)戰(zhàn)項(xiàng)目課程—CAT安裝使用-GateWay網(wǎng)關(guān)服務(wù)搭建

    網(wǎng)關(guān)JAVA編程語(yǔ)言Gate網(wǎng)關(guān)設(shè)備
    Mr_haohao
    發(fā)布于 :2022年09月05日 07:17:38

    cc2530和linux gateway之間的通信網(wǎng)關(guān)端的服務(wù)都沒有正常啟動(dòng)是什么原因?

    點(diǎn)。我希望通過中心節(jié)點(diǎn)去控制端節(jié)點(diǎn)。另外在網(wǎng)關(guān)端我安裝了Z-Stack_Linux_Gateway-1.0.1,即TI的gateway上的SDK,現(xiàn)在我遇到了些問題: 網(wǎng)關(guān)上運(yùn)行zig
    發(fā)表于 08-14 07:43

    Thing***oard之Gateway使用示例有哪些

    Thing***oard之Gateway使用示例國(guó)慶期間西安陰雨綿綿,閑來無(wú)事,把thing***orad運(yùn)行搭建起來,體驗(yàn)了一把??傮w來講CE版本還是很棒的,提供了物聯(lián)網(wǎng)平臺(tái)該有的基礎(chǔ)能力
    發(fā)表于 07-12 07:51

    服務(wù)網(wǎng)關(guān)gateway的相關(guān)資料推薦

    目錄微服務(wù)網(wǎng)關(guān) gateway 概述[路由器網(wǎng)關(guān) Zuul 概述]嵌入式 Zuul 反向代理微服務(wù)網(wǎng)關(guān) gateway 概述1、想象一下一個(gè)
    發(fā)表于 12-23 08:19

    [魯班貓創(chuàng)意氛圍賽]項(xiàng)目提交:本地LoRaWAN網(wǎng)關(guān)

    chirpstack-gateway-bridge 橋接器,橋接集中器與服務(wù)器之間的通訊 chirpstack 服務(wù)器,用來管理集中器,設(shè)備等角色,并管理數(shù)據(jù),設(shè)備描述等,相關(guān)數(shù)據(jù)保存在數(shù)據(jù)庫(kù)里 當(dāng)前
    發(fā)表于 05-13 16:11

    利用Gateway實(shí)現(xiàn)上位機(jī)監(jiān)控

    前言此技術(shù)文件用于介紹觸控大師的Gateway Server(網(wǎng)關(guān)服務(wù))的設(shè)定與使用方式。用戶可以通過這個(gè)功能來實(shí)現(xiàn)上位機(jī)局域網(wǎng)遠(yuǎn)程監(jiān)控的功能。特點(diǎn)􀁺提供 1 個(gè)以太
    發(fā)表于 11-29 16:00 ?0次下載
    <b class='flag-5'>利用</b><b class='flag-5'>Gateway</b>實(shí)現(xiàn)上位機(jī)監(jiān)控

    六、利用ESP32搭建網(wǎng)絡(luò)服務(wù)器(一)

    六、利用ESP32搭建網(wǎng)絡(luò)服務(wù)器(一)歡迎使用Markdown編輯器新的改變功能快捷鍵合理的創(chuàng)建標(biāo)題,有助于目錄的生成如何改變文本的樣式插入鏈接與圖片如何插入一段漂亮的代碼片生成一個(gè)適合你的列表創(chuàng)建
    發(fā)表于 12-29 19:00 ?3次下載
    六、<b class='flag-5'>利用</b>ESP32<b class='flag-5'>搭建網(wǎng)絡(luò)服務(wù)</b>器(一)

    網(wǎng)站搭建時(shí)該如何選擇租用服務(wù)

    搭建網(wǎng)站的時(shí)候是必須要用到服務(wù)器。服務(wù)器分很多種,有用來開發(fā)游戲叫游戲服務(wù)器,用來存放數(shù)據(jù)叫數(shù)據(jù)庫(kù)服務(wù)器,有應(yīng)用
    發(fā)表于 03-14 09:44 ?872次閱讀

    Dubbo Gateway基于Java的Dubbo網(wǎng)關(guān)實(shí)現(xiàn)

    ./oschina_soft/dubbo-gateway.zip
    發(fā)表于 06-14 10:28 ?3次下載
    Dubbo <b class='flag-5'>Gateway</b>基于Java的Dubbo<b class='flag-5'>網(wǎng)關(guān)</b>實(shí)現(xiàn)

    Spring Cloud Gateway服務(wù)網(wǎng)關(guān)的部署與使用詳細(xì)教程

    Gateway 網(wǎng)關(guān)搭建: 3、Spring Cloud Gateway 配置項(xiàng)的說明: 4、Gateway 集成 nacos 注冊(cè)中心
    的頭像 發(fā)表于 10-11 17:46 ?1672次閱讀

    如何使用Gateway搭建網(wǎng)關(guān)服務(wù)及實(shí)現(xiàn)動(dòng)態(tài)路由?

    網(wǎng)關(guān)作為請(qǐng)求統(tǒng)一入口,路由就相當(dāng)于是每個(gè)業(yè)務(wù)系統(tǒng)的入口,通過路由規(guī)則則可以匹配到對(duì)應(yīng)微服務(wù)的入口,將請(qǐng)求命中到對(duì)應(yīng)的業(yè)務(wù)系統(tǒng)中
    的頭像 發(fā)表于 11-15 10:12 ?1423次閱讀

    新品速遞 | 虹科CAN FD轉(zhuǎn)LAN網(wǎng)關(guān):PCAN-Ethernet Gateway FD DR

    PCAN-Ethernet Gateway FD DR網(wǎng)關(guān)可以通過IP網(wǎng)絡(luò)訪問傳統(tǒng)CAN總線或CAN FD總線。
    的頭像 發(fā)表于 11-03 17:43 ?1277次閱讀
    新品速遞 | 虹科CAN FD轉(zhuǎn)LAN<b class='flag-5'>網(wǎng)關(guān)</b>:PCAN-Ethernet <b class='flag-5'>Gateway</b> FD DR

    網(wǎng)關(guān)GateWay的基本概念和使用詳解

    SpringCloudGateway網(wǎng)關(guān)是所有微服務(wù)的統(tǒng)一入口。
    的頭像 發(fā)表于 08-08 09:39 ?2146次閱讀
    <b class='flag-5'>網(wǎng)關(guān)</b><b class='flag-5'>GateWay</b>的基本概念和使用詳解

    Spring Cloud Gateway網(wǎng)關(guān)框架

    Spring Cloud Gateway網(wǎng)關(guān)框架 本軟件微服務(wù)架構(gòu)中采用Spring Cloud Gateway網(wǎng)關(guān)控制框架,Spring
    的頭像 發(fā)表于 08-22 09:58 ?382次閱讀
    Spring Cloud <b class='flag-5'>Gateway</b><b class='flag-5'>網(wǎng)關(guān)</b>框架