微服务网关-Spring Cloud Gateway(下)

本文涉及的产品
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 微服务网关-Spring Cloud Gateway(下)

正文


六、动态网关


动态网管可以使用配置中心,Redis,和数据库(我用的方法)

直接上代码,其实就是增删改查


package com.xiaojie.entity;
import lombok.Data;
/**
 * @Description: 路由实体类
 * @author: xiaojie
 * @date: 2021.07.15
 */
@Data
public class Route {
    private Integer id;
    private String routeId; //路由id
    private String routeName;//路由名称
    private String routePattern;//路由转发地址,
    private Integer routeType;//路由类型1从注册中心获取,0-转发地址
    private String routeUrl;//转发到的地址
    private Integer isOpen;//是否开放0-否1-开放
    private Integer isUse;//是否可用0-否1-开放
}


package com.xiaojie.mapper;
import com.xiaojie.entity.Route;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
 * @Description:Mapper接口
 * @author: xiaojie
 * @date: 2021.07.15
 */
public interface RouteMapper {
    @Select("SELECT id,routeId,routeName,routePattern,routeType,routeUrl,is_open isOpen,is_use isUse FROM `tb_route` WHERE is_open=1 and is_use=1;")
    List<Route> selectAllRoute();
    @Insert("INSERT INTO tb_route(routeId,routeName,routePattern,routeType,routeUrl,is_open,is_use) " +
            "VALUES(#{routeId},#{routeName},#{routePattern},#{routeType},#{routeUrl},#{isOpen},#{isUse})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    Integer add(Route route);
    @Update("UPDATE tb_route set routePattern=#{routePattern},routeUrl=#{routeUrl} WHERE routeId=#{routeId}")
    Integer update(Route route);
    @Delete("DELETE FROM tb_route WHERE routeId=#{routeId}")
    Integer delete(String routeId);
}


package com.xiaojie.service.impl;
import com.xiaojie.entity.Route;
import com.xiaojie.mapper.RouteMapper;
import com.xiaojie.service.RouteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @Description:
 * @author: xiaojie
 * @date: 2021.07.15
 */
@Service
@Slf4j
public class RouteServiceImpl  implements RouteService, ApplicationEventPublisherAware {
    private ApplicationEventPublisher applicationEventPublisher;
    @Autowired
    private RouteMapper routeMapper;
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    @Override
    public List<Route> getAll() {
        List<Route> routes = routeMapper.selectAllRoute();
        for (Route  route: routes){
            loadRoute(route);
        }
        return routes;
    }
    public void loadRoute(Route route) {
        RouteDefinition definition = new RouteDefinition();
        Map<String, String> predicateParams = new HashMap<>(8);
        PredicateDefinition predicate = new PredicateDefinition();
        FilterDefinition filterDefinition = new FilterDefinition();
        Map<String, String> filterParams = new HashMap<>(8);
        URI uri = null;
        if (1==route.getRouteType()) {
            // 如果配置路由type为1的话 则从注册中心获取服务地址
            uri = UriComponentsBuilder.fromUriString(route.getRouteUrl()).build().toUri();
        } else {
            uri = UriComponentsBuilder.fromHttpUrl(route.getRouteUrl()).build().toUri();
        }
        // 定义的路由唯一的id
        definition.setId(route.getRouteId());
        predicate.setName("Path");
        //路由转发地址
        predicateParams.put("pattern", route.getRoutePattern());
        predicate.setArgs(predicateParams);
        filterDefinition.setName("StripPrefix");
        filterParams.put("_genkey_0", "1");
        filterDefinition.setArgs(filterParams);
        definition.setPredicates(Arrays.asList(predicate));
        definition.setFilters(Arrays.asList(filterDefinition));
        definition.setUri(uri);
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
        log.info("路由刷新成功.............................");
    }
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher=applicationEventPublisher;
    }
}


定义接口,当修改路由之后,需要刷新路由规则


  @RequestMapping("/refreshGw")
    public Object refreshGw() {
        return routeService.getAll();
    }


SQL如下


/*
 Navicat MySQL Data Transfer
 Source Server         : 本地
 Source Server Type    : MySQL
 Source Server Version : 80024
 Source Host           : localhost:3306
 Source Schema         : my_test
 Target Server Type    : MySQL
 Target Server Version : 80024
 File Encoding         : 65001
 Date: 15/07/2021 15:25:24
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for tb_route
-- ----------------------------
DROP TABLE IF EXISTS `tb_route`;
CREATE TABLE `tb_route`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `routeId` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '路由id',
  `routeName` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '路由名称',
  `routePattern` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '路由转发地址',
  `routeType` tinyint NULL DEFAULT NULL COMMENT '路由类型1从注册中心获取,0-转发地址',
  `routeUrl` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '转发到的地址',
  `is_open` tinyint NULL DEFAULT NULL COMMENT '是否开放0-否1-开放',
  `is_use` tinyint NULL DEFAULT NULL COMMENT '是否可用0-否1-开放',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '动态网关表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of tb_route
-- ----------------------------
INSERT INTO `tb_route` VALUES (1, 'member', 'xiaojie-member', '/member/**', 1, 'lb://xiaojie-member/', 1, 1);
INSERT INTO `tb_route` VALUES (3, 'baidu', 'xiaojie-baidu', '/bai/**', 0, 'http://www.baidu.com', 1, 1);
SET FOREIGN_KEY_CHECKS = 1;


配置文件如下


server:
  port: 82
####服务网关名称
spring:
  application:
    name: xiaojie-gateway
  cloud:
    gateway:
          ###路由策略
                discovery:
                  locator:
                    enabled: true
    nacos:
      discovery:
        #注册地址
        server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850
        #是否开启nacos注册
        enabled: true
        #账号
        username: xiaojie
        #密码
        password: nacos
        #命名空间
        namespace: 28eb29ea-5a04-4714-8ae8-77d37c01166a
        #分组
        group: DEV_GROUP
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    filters: stat
    initialSize: 10
    maxActive: 50
    maxOpenPreparedStatements: 20
    maxWait: 60000
    minEvictableIdleTimeMillis: 300000
    minIdle: 10
    password: root
    poolPreparedStatements: true
    testOnBorrow: false
    testOnReturn: false
    testWhileIdle: true
    timeBetweenEvictionRunsMillis: 60000
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://127.0.0.1:3306/my_test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&autoReconnect=true
    username: root
    validationQuery: select 1


七、网关解决跨域


package com.xiaojie.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
 * @Description: 解决微服务的跨域问题
 * @Author: yan
 * @Date: 2021/5/12 23:18
 * @return: null
 **/
@Component
public class CrossOriginFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        HttpHeaders headers = response.getHeaders();
        headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
        headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, PUT, OPTIONS, DELETE, PATCH");
        headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
        headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
        headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
        return chain.filter(exchange);
    }
}


八、网关实现限流


使用的算法是令牌桶 Redis+Lua


令牌流与令牌桶


系统会以一定的速度生成令牌,并将其放置到令牌桶中,可以将令牌桶想象成一个缓冲区(可以用队列这种数据结构来实现),当缓冲区填满的时候,新生成的令牌会被扔掉。 这里有两个变量很重要:


第一个是生成令牌的速度,一般称为 rate 。比如,我们设定 rate = 2 ,即每秒钟生成 2 个令牌,也就是每 1/2 秒生成一个令牌;

第二个是令牌桶的大小,一般称为 burst 。比如,我们设定 burst = 10 ,即令牌桶最大只能容纳 10 个令牌。


数据流


数据流是真正的进入系统的流量,对于接口来讲,如果平均每秒钟会调用2次,则认为速率为 2次/s 。


算法原理


系统接收到一个单位数据(对于网络传输,可以是一个包或者一个字节;对于微服务,可以是一个请求)后,从令牌桶中取出一个令牌,然后对数据或请求进行处理。如果令牌桶中没有令牌了,会直接将数据或者请求丢弃。当然,对于微服务,就不能是丢弃这么简单了:可以返回一个异常消息,用于提示用户其请求速率超过了系统限制。


有以下三种情形可能发生:


数据流的速率 等于 令牌流的速率。这种情况下,每个到来的数据包或者请求都能对应一个令牌,然后无延迟地通过队列;

数据流的速率 小于 令牌流的速率。通过队列的数据包或者请求只消耗了一部分令牌,剩下的令牌会在令牌桶里积累下来,直到桶被装满。剩下的令牌可以在突发请求的时候消耗掉。

数据流的速率 大于 令牌流的速率。这意味着桶里的令牌很快就会被耗尽。导致服务中断一段时间,如果数据包或者请求持续到来,将发生丢包或者拒绝响应。

比如前面举的例子,生成令牌的速率和令牌桶的大小分别为 rate = 2, burst = 10 ,则系统能承受的突发请求速率为 10次/s ,平均请求速率为 2次/s 。


摘自:https://blog.csdn.net/xgw1010/article/details/107595141


代码如下

package com.xiaojie.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
/**
 * @Description:
 * @author: xiaojie
 * @date: 2021.07.16
 */
@Configuration
public class MyKeyResolver {
    /*
     *  ip限流 每一个ip只能在限流的规则内访问的规则,超出规则,进行限流
     * @todo
     * @author xiaojie
     * @date 2021/7/16 9:44
     * @return org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
     */
//    @Bean("ipKeyResolver")
//    @Primary
//    public KeyResolver ipKeyResolver() {
//        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostString());
//    }
    /*
     *  用户限流 每一个用户的限流规则 访问时需要携带userId 参数
     * @todo
     * @author xiaojie
     * @date 2021/7/16 9:44
     * @return org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
     */
    @Bean("userKeyResolver")
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
    }
    /*
     * 接口限流 根据接口路径限流
     * @todo
     * @author xiaojie 
     * @date 2021/7/16 9:45 
     * @return org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
     */
//    @Bean("apiKeyResolver")
//    KeyResolver apiKeyResolver() {
//        return exchange -> Mono.just(exchange.getRequest().getPath().value());
//    }
}


路由配置如下


server:
  port: 82
####服务网关名称
spring:
  application:
    name: xiaojie-gateway
  cloud:
    gateway:
          ###路由策略
#          routes:
#            ###根据我们的服务名称查找地址实现调用
#            - id: member
#              #uri: http://127.0.0.1:8090
#              uri: lb://xiaojie-member/
#              filters:
#                - StripPrefix=1
#              ###匹配规则
#              predicates:
#                - Path=/member/*
                routes:
                  - id: requestratelimiter_route
                    uri: lb://xiaojie-member/
                    filters:
                      - name: RequestRateLimiter
                        args:
                          #允许用户每秒执行多少请求,而没有任何丢弃的请求。这是令牌桶填充的速率
                          redis-rate-limiter.replenishRate: 1
                          #允许用户在一秒内执行的最大请求数。这是令牌桶可以容纳的令牌数量。将此值设置为零会阻止所有请求。
                          redis-rate-limiter.burstCapacity: 1
                          #每个请求从存储桶中获取的令牌数量,默认为 1
                          redis-rate-limiter.requestedTokens: 1
                          key-resolver:
                            - "#{@userKeyResolver}" #根据用户限流
                      - StripPrefix=1
                    predicates:
                      - Path=/member/*
                #从注册中心获取服务
                discovery:
                  locator:
                    enabled: true
    nacos:
      discovery:
        #注册地址
        server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850
        #是否开启nacos注册
        enabled: true
        #账号
        username: xiaojie
        #密码
        password: nacos
        #命名空间
        namespace: 28eb29ea-5a04-4714-8ae8-77d37c01166a
        #分组
        group: DEV_GROUP
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    filters: stat
    initialSize: 10
    maxActive: 50
    maxOpenPreparedStatements: 20
    maxWait: 60000
    minEvictableIdleTimeMillis: 300000
    minIdle: 10
    password: root
    poolPreparedStatements: true
    testOnBorrow: false
    testOnReturn: false
    testWhileIdle: true
    timeBetweenEvictionRunsMillis: 60000
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://127.0.0.1:3306/my_test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&autoReconnect=true
    username: root
    validationQuery: select 1
    #基于redis实现限流
  redis:
    host: 192.168.6.130
    password: xiaojie
    port: 6379


限流后返回429状态码


动态限流 基于Sentinel


九、设置黑白名单


package com.xiaojie.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
/**
 * @Description: 黑名单
 * @author: xiaojie
 * @date: 2021.07.16
 */
@Component
@Slf4j
public class IpFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String ipAddress = getIpAddress(request);
        log.info("获取的IP地址为{}",ipAddress);
        //实际生产可以基于redis,数据库实现记录
        if ("127.0.0.1".equals(ipAddress)){
            ServerHttpResponse response = exchange.getResponse();
            HttpHeaders httpHeaders = response.getHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            String msg="已被加入黑名单";
            DataBuffer buffer = response.bufferFactory().wrap(msg.getBytes());
            return response.writeWith(Mono.just(buffer));
        }
        return chain.filter(exchange);
    }
    /*
     * 获取用户真实ip 
     * @todo
     * @author xiaojie 
     * @date 2021/7/16 14:52
     * @return java.lang.String
     */
    public static String getIpAddress(ServerHttpRequest  request) {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }
        return ip;
    }
}


参考:https://blog.csdn.net/lizz861109/article/details/108530364


https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-prefixpath-gatewayfilter-factory


https://blog.csdn.net/qq_32652767/article/details/112257082


https://blog.csdn.net/xgw1010/article/details/107595141


感谢几位大佬

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
24天前
|
JSON Java API
利用Spring Cloud Gateway Predicate优化微服务路由策略
Spring Cloud Gateway 的路由配置中,`predicates`​(断言)用于定义哪些请求应该匹配特定的路由规则。 断言是Gateway在进行路由时,根据具体的请求信息如请求路径、请求方法、请求参数等进行匹配的规则。当一个请求的信息符合断言设置的条件时,Gateway就会将该请求路由到对应的服务上。
134 69
利用Spring Cloud Gateway Predicate优化微服务路由策略
|
8天前
|
搜索推荐 NoSQL Java
微服务架构设计与实践:用Spring Cloud实现抖音的推荐系统
本文基于Spring Cloud实现了一个简化的抖音推荐系统,涵盖用户行为管理、视频资源管理、个性化推荐和实时数据处理四大核心功能。通过Eureka进行服务注册与发现,使用Feign实现服务间调用,并借助Redis缓存用户画像,Kafka传递用户行为数据。文章详细介绍了项目搭建、服务创建及配置过程,包括用户服务、视频服务、推荐服务和数据处理服务的开发步骤。最后,通过业务测试验证了系统的功能,并引入Resilience4j实现服务降级,确保系统在部分服务故障时仍能正常运行。此示例旨在帮助读者理解微服务架构的设计思路与实践方法。
52 16
|
1月前
|
Java Nacos Sentinel
Spring Cloud Alibaba:一站式微服务解决方案
Spring Cloud Alibaba(简称SCA) 是一个基于 Spring Cloud 构建的开源微服务框架,专为解决分布式系统中的服务治理、配置管理、服务发现、消息总线等问题而设计。
288 13
Spring Cloud Alibaba:一站式微服务解决方案
|
1月前
|
JavaScript Java Kotlin
深入 Spring Cloud Gateway 过滤器
Spring Cloud Gateway 是新一代微服务网关框架,支持多种过滤器实现。本文详解了 `GlobalFilter`、`GatewayFilter` 和 `AbstractGatewayFilterFactory` 三种过滤器的实现方式及其应用场景,帮助开发者高效利用这些工具进行网关开发。
241 1
|
1月前
|
负载均衡 Java 开发者
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
163 5
|
1月前
|
Prometheus 监控 Java
如何全面监控所有的 Spring Boot 微服务
如何全面监控所有的 Spring Boot 微服务
95 3
|
2月前
|
负载均衡 Java API
项目中用的网关Gateway及SpringCloud
Spring Cloud Gateway 是一个功能强大、灵活易用的API网关解决方案。通过配置路由、过滤器、熔断器和限流等功能,可以有效地管理和保护微服务。本文详细介绍了Spring Cloud Gateway的基本概念、配置方法和实际应用,希望能帮助开发者更好地理解和使用这一工具。通过合理使用Spring Cloud Gateway,可以显著提升微服务架构的健壮性和可维护性。
67 0
|
4月前
|
负载均衡 Java Nacos
SpringCloud基础2——Nacos配置、Feign、Gateway
nacos配置管理、Feign远程调用、Gateway服务网关
SpringCloud基础2——Nacos配置、Feign、Gateway
|
4月前
|
Java 开发者 Spring
Spring Cloud Gateway 中,过滤器的分类有哪些?
Spring Cloud Gateway 中,过滤器的分类有哪些?
108 3
|
4月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
214 5