当前位置: 首页>后端>正文

SpringCloud入门 —— Zuul路由配置

一、Zuul是什么?

Zuul 是 Netflix OSS 中的一员,是一个基于 JVM 路由器服务端的负载均衡器。提供路由、监控、弹性、安全等方面的服务框架。Zuul 能够与 Eureka、Ribbon、Hystrix 等组件配合使用。

zuul核心功能是过滤器、路由、异常处理,通过过滤器还能扩展出其他功能:

1)动态路由、2)请求监控、3)认证鉴权、4)压力测试、5)灰度发布

二、Zuul路由配置

1.创建项目

在之前的项目上,新建一个springboot项目:zuul-server,继承parent。


SpringCloud入门 —— Zuul路由配置,第1张

引入依赖:

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

<!--Zuul-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

这里有个问题:

spring-cloud-starter-netflix-zuul:2.2.x 和Spring Boot 2.5.x之间的Spring 版本冲突
Spring Boot 2.4之后不支持zuul(改用Gateway)

导致项目启动失败,请戳解决方法

2.路由规则配置

当 Zuul 集成 Eureka 之后,其实就可以为 Eureka 中所有的服务进行路由操作了,默认的转发规则就是“API 网关地址+访问的服务名称+接口 URI”。

配置文件如下:

server.port=8088
#server.servlet.context-path=/zuul-demo
spring.application.name=zuul-server

eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka/

#zuul代理配置  zuul.routes.服务名.path,服务名要与注册的一致
zuul.routes.client-provider-server.path=/client-provider/**
#URL映射
#zuul.routes.client-provider-server.url=http://localhost:8081/
#应用名映射
zuul.routes.client-provider-server.service-id=client-provider-server

启动类设置@EnableZuulProxy注解,访问代理 http://localhost:8088/client-provider/api/provider

SpringCloud入门 —— Zuul路由配置,第2张

3.Zuul过滤器介绍及使用

Zuul 中的过滤器跟我们之前使用的 javax.servlet.Filter 不一样,javax.servlet.Filter 只有一种类型,可以通过配置 urlPatterns 来拦截对应的请求。

过滤器类型

类型 使用场景
pre 可以在请求被路由之前调用。适用于身份认证的场景,认证通过后再继续执行下面的流程。
route 在路由请求时被调用。适用于灰度发布场景,在将要路由的时候可以做一些自定义的逻辑。
error 处理请求时发生错误时被调用。在执行过程中发送错误时会进入 error 过滤器,可以用来统一记录错误信息。
post 在 route 和 error 过滤器之后被调用。这种过滤器将请求路由到达具体的服务之后执行。适用于需要添加响应头,记录响应日志等应用场景。

过滤器执行生命周期

SpringCloud入门 —— Zuul路由配置,第3张
过滤器生命周期

通过上面的图可以清楚地知道整个执行的顺序,请求发过来首先到 pre 过滤器,再到 routing 过滤器,最后到 post 过滤器,任何一个过滤器有异常都会进入 error 过滤器。

自定义Zuul过滤器

如下,代码说明写在注释中

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;

/**
 * 自定义过滤器
 */
public class MyAccessFilter extends ZuulFilter {

    /**
     * 过滤器类型,可选值有 pre、route、post、error。
     *
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 通过int值来定义过滤器的执行顺序
     * 过滤器的执行顺序,数值越小,优先级越高。
     *
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否执行该过滤器,true 为执行,false 为不执行
     * 这个也可以利用配置中心来实现,达到动态的开启和关闭过滤器。
     * 配置文件中禁用过滤器:
     * 【zuul.过滤器的类名.过滤器类型.disable=true,如:zuul.MyAccessFilter.pre.disable=true】
     *
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 过滤器具体逻辑
     *
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        System.out.println(String.format("%s AccessFilter request to %s", request.getMethod(), request.getRequestURL().toString()));
        String accessToken = request.getParameter("accessToken");
        // 有权限令牌
        if (!StringUtils.isEmpty(accessToken)) {
            // 设置是否路由到服务
            ctx.setSendZuulResponse(true);
            ctx.setResponseStatusCode(200);
            // 设置下一个过滤器是否执行,当为 true 的时候,后续的过滤器才执行,若为 false 则不执行。
            ctx.set("isSuccess", true);
        } else {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("{\"result\":\"accessToken is not correct!\"}");
            //可以设置一些值
            ctx.set("isSuccess", false);
        }
        return null;
    }
}

配置过滤器

import com.local.springboot.zuul.zuulserver.filter.MyAccessFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfiguration {

    @Bean
    public MyAccessFilter myAccessFilter(){
        return new MyAccessFilter();
    }
}

访问:http://localhost:8088/client-provider/api/provider

SpringCloud入门 —— Zuul路由配置,第4张

重新访问:http://localhost:8088/client-provider/api/provider?accessToken=12358
SpringCloud入门 —— Zuul路由配置,第5张

异常处理

与Spring Boot中用 @ControllerAdvice 注解统一异常处理不同,@ControllerAdvice 注解主要用来针对 Controller 中的方法做处理,作用于 @RequestMapping 标注的方法上,只对我们定义的接口异常有效,在 Zuul 中是无效的。

我们可以定义一个 error 过滤器来记录异常信息或者通过实现ErrorController 的方式处理异常。

public class ErrorFilter extends ZuulFilter {
    private Logger log = LoggerFactory.getLogger(ErrorFilter.class);
    @Override
    public String filterType() {
        return "error";
    }
    @Override
    public int filterOrder() {
        return 10;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        Throwable throwable = ctx.getThrowable();
        log.error("Filter Erroe : {}", throwable.getCause().getMessage());
        return null;
    }
}

动态路由

Zuul 实现动态路由,是因为Zuul 集成的有负载均衡、有负载均衡的效果。详情请戳SpringCloud入门 —— Ribbon负载均衡

求关注,定期分享Java知识,一起学习,共同成长。

? 上一章:SpringCloud入门 —— Ribbon负载均衡
? 下一章:SpringCloud入门 —— SSO 单点登录


https://www.xamrdz.com/backend/3be1936044.html

相关文章: