5-Spring Cloud微服务快速搭建-网关-(zuul、gateway-路由配置,过滤器,路径重写,限流-未完善)

修订日期内容
2021-2-22初稿

zuul网关

简介

zuul网关由netflix开发的开源的微服务网关,zuul网关的核心是一系列的过滤器,这些过滤器注意有以下功能

  1. 动态路由:将不同的请求分发到不同的服务器
  2. 压力测试:逐渐增加流量
  3. 负载设置:为每一种负载类型增加对应的容器,并放弃超出限定的请求
  4. 静态响应处理:如css,js的文件避免服务转发到内部
  5. 身份认证:对每一份资源进行安全验证

搭建zuul网关

  1. 创建工程导入依赖
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
 </dependency>
  1. 使用注解@EnableZuulProxy

  2. 配置路由

  • 基础配置法(类似与Nginx的功能,不推荐)
# 路径设置
zuul:
  routes:
    express-service: # 服务名
      path: /express-service/** # 映射路径 如:localhost://express-serivce/query/1
      url: http://localhost:8001 # 实际映射地址
  • 服务名配置法(配合eureka使用,这才是正确的打开方式)
    1,先接入eureka,接入eureka服务请参考待补充链接
zuul:
  routes:
    express-service: # 路由名-随便定义
      path: /express-service/** # 映射路径 如:localhost://express-serivce/express/query/1
      # 面向服务配置 express-service为注册到eureka的服务名
      serviceId: express-service

上述配置可以继续简化(依然不推荐):

zuul:
  routes:
    express-service: /express-service/**  # 简化配置(express-service 一定要存在,不能随便定义)

终极配置

zuul:
  routes:
    # express-service: /express-service/**  # 可以省略,zuul会根据eureka中的服务名自动路由转发

【坑点】新手注意,zuul使用eureka接入服务时,如果响应时间超过1秒会报如下错误

前端报错:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing >this as a fallback.
Tue Feb 23 23:13:38 CST 2021
There was an unexpected error (type=Gateway Timeout, status=504).

后端报错:
com.netflix.zuul.exception.ZuulException:
at org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter.findZuulException(SendErrorFilter.java:118) ~[spring-cloud-netflix-zuul-2.2.7.RELEASE.jar:2.2.7.RELEASE]
at org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter.run(SendErrorFilter.java:78) ~[spring-cloud-netflix-zuul-2.2.7.RELEASE.jar:2.2.7.RELEASE]

解决方案:调整负载均衡ribbon的超时时间

ribbon:
  ReadTimeout: 3000
  SocketTimeout: 3000

zuul 网关过滤器

过滤器类型介绍

  • pre : 在转发微服务之前调用
  • routing 在调用微服务时调用
  • post 在微服务返回了结果时调用
  • error 在整个阶段抛出异常时调用

zuul的执行过程图:
zull网关过滤器执行位置图

创建一个过滤器

创建一个类,继承ZuulFilter即可

@Component
public class LoginFilter extends ZuulFilter {

    private Logger logger = LoggerFactory.getLogger(LoginFilter.class);

    /**
     * 过滤器类型,
     * pre,routing,post,error
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 过滤器的执行顺序,当有多个过滤器时实现的顺序,数字越小越先执行
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否开启,true开启,false 关闭
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 过滤的业务逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        logger.info("执行了过滤器");
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        String token = request.getParameter("token");
        if(StringUtils.isEmpty(token)){
            //直接拦截请求
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseBody("token验证不通过");
            currentContext.getResponse().setCharacterEncoding("UTF-8");
            currentContext.getResponse().setContentType("text/html;cahrset=UTF-8");
        }
        return null;
    }
}

Spring Cloud Gateway

由于zuul存在一些问题,
①本质是一个同步的servlet,既每一个请求过来都会分配一个线程来处理对应的请求直到客户端响应才会释放。
②zuul不支持长链接,如:webscoket
我们可以采用其他的替换方案 spring cloud gateway

整合

  • 基本路由配置

  1. 引入maven依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- 如果父工程中有引入spring-web可以使用此方式巧妙剔除spring-web的依赖-->
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <scope>test</scope>
  </dependency>

注意spring gateway 是通过Netty+webflux实现,与tomcat会有冲突,所以子项目与父工程都不能引入spring-web

  1. 启动项
@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(GatewayApplication.class).run(args);

    }
}
  1. 配置路由信息
  • 配置方式一基本路由配置(不推荐)
server:
  port: 8087

spring:
  application:
    name: gateway-service-demo
  cloud:
    gateway:
      routes:
        - id: express-service
          uri: http://localhost:8082
          predicates: # 路由规则
            - Path=/express/** # 路由条件 注意这里例子:的express不能随便命名,配置需要拦截的真实url路径,如原服务url:http://localhost:8082/express/query/1,则此处路由条件要配置express
  • 测试
    原服务路径url:http://localhost:8082/express/query/1
    启动geteway网关后的路径:http://localhost:8087/express/query/1
  • 动态路由配置(半推荐)

    • ①引入注册中心依赖,并注册
<!-- 引入eureka客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
  • 修改配置文件并启动服务
spring:
  application:
    name: gateway-service-demo
  cloud:
    gateway:
      routes:
        - id: express-service
          uri: lb://express-service # lb标示根据微服务名称路由
          predicates: # 路由规则
            - Path=/express/** # 路由条件 path路由配置

server:
  port: 8088

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
  instance:
    ip-address: true # 使用ip地址注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port} # 向注册中心注册服务ip

ribbon:
  ReadTimeout: 3000
  SocketTimeout: 3000

路径重写过滤器filter

如:原真实URL:http://localhost:8082/express/query/1
使用gateway后期望的URL:http://localhost:8088/api/express/query/1

这里可以使用gateway的过滤器filter实现

spring:
  application:
    name: gateway-service-demo
  cloud:
    gateway:
      routes:
        - id: express-service
          uri: lb://express-service # lb标示根据微服务名称路由
          predicates: # 路由规则
            - Path=/api/** # 路由条件 path路由配置 注意这里的api与下面的路径过滤器中的api要一致,否则无法拦截
          filters:
            - RewritePath=/api/(?<segment>.*), /$\{segment}   #路径重写的过滤器,在yml中$写为$\

配置自动根据微服务名称进行路由转发(推荐)

上述的配置略微有点复杂,有一种更为简单的配置方式

spring:
  application:
    name: gateway-service-demo
  cloud:
    gateway:
      # 自动根据微服务名称路由转发 ,真实地址:http://localhost:8082/express/query/1,启用后:http://localhost:8088/express-service/express/query/1
      discovery:
        locator:
          enabled: true # 开启
          lower-case-service-id: true # 使用微服务小写名称

spring gateway 全局过滤器

实现org.springframework.cloud.gateway.filter.GlobalFilter接口即可,如一下例子实现登录验证

@Component
public class LoginFilter implements GlobalFilter, Ordered {

    private Logger logger = LoggerFactory.getLogger(LoginFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        logger.info("执行了全局过滤器...");
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if(token == null){
            logger.error("没有登录信息...");
            //返回码:401, "Unauthorized"
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            //完成请求
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

	//请求顺序,多拦截器执行的顺序,越小越先执行
    @Override
    public int getOrder() {
        return 0;
    }
}

测试:
http://localhost:8088/express-service/express/query/1 -无法执行
http://localhost:8088/express-service/express/query/1?token=1 -请求成功

网关限流

基于filter限流

spring gateway 支持令牌桶算法,基于内置的过滤器实现,在过滤器中使用redis与lua脚本实现
准备工作:

  • 安装redis
  • 引入redis相关依赖
  • 配置
<!-- 监控相关依赖-->
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>

– 待补充

基于sentinel限流

1.引入sentinel对gateway的相关依赖

<dependency>
   <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值