Zuul的核心是过滤器,通过这些过滤器我们可以扩展出很多功能,比如:
- 动态路由:动态地将客户端的请求路由到后端不同的服务,做一些逻辑处理,比如聚合多个服务的数据返回。
请求监控:可以对整个系统的请求进行监控,记录详细的请求响应日志,可以实时统计出当前系统的访问量以及监控状态。 - 认证鉴权:对每一个访问的请求做认证,拒绝非法请求,保护好后端的服务。
- 压力测试:压力测试是一项很重要的工作,像一些电商公司需要模拟更多真实的用户并发量来保证重大活动时系统的稳定。通过Zuul可以动态地将请求转发到后端服务的集群中,还可以识别测试流量和真实流量,从而做一些特殊处理。
- 灰度发布:灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。
使用Zuul构建微服务网关
-
基本环境
参考:https://blog.csdn.net/admin_15082037343/article/details/107134802 -
新建子模块:demo-zuul,添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
- 启动类
package com.demo.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
- application.yml
server:
port: 8080
spring:
application:
name: demo-zuul
zuul:
routes:
demo-client:
path: /user/**
eureka:
client:
service-url:
defaultZone: http://admin:123456@127.0.0.1:8761/eureka/
这里表示对/user/**的访问会转发到demo-client上
访问http://127.0.0.1:8080/user/user/4028a881727903dc017279105f520002
Zuul过滤器类型
Zuul中的过滤器总共有4种类型,每种类型都有对应的使用场景。
- pre:可以在请求被路由之前调用。适用于身份认证的场景,认证通过后再继续执行下面的流程。
- route:在路由请求时被调用。适用于灰度发布场景,在将要路由的时候可以做一些自定义的逻辑。
- post:在route和error过滤器之后被调用。这种过滤器将请求路由到达具体的服务之后执行。适用于需要添加响应头,记录响应日志等应用场景。
- error:处理请求时发生错误时被调用。在执行过程中发送错误时会进入error过滤器,可以用来统一记录错误信息。
定义一个pre类型的过滤器
package com.demo.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component;
@Component
public class MyFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
// 当前请求上下文
RequestContext requestContext = RequestContext.getCurrentContext();
String name = requestContext.getRequest().getParameter("name");
if (name == null || name.trim().isEmpty()) {
// 不需要将当前请求转发到后端
requestContext.setSendZuulResponse(false);
// 客户端响应
requestContext.setResponseBody("error");
}
return null;
}
}
filterOrder():当前过滤器的执行顺序,数字越小越先执行
shouldFilter():true代表执行当前过滤器,false代表不执行
run():逻辑处理,RequestContext.getCurrentContext()获取当前请求上下文。
RequestContext对象的set()方法可以向下一个过滤器传递参数,如下:
// 存值
requestContext.set("name", "zhangsan");
// 取值
requestContext.get("name")