一、Zuul
- 不同的微服务一般有不同的网络地址,而外部的客户端可能需要调用多个服务的接口才 能完成一个业务需求。比如一个电影购票的手机 APP,可能会调用电影分类微服务,用户微 服务,支付微服务等。如果客户端直接和微服务进行通信,会存在以下问题:
- 客户端会多次请求不同微服务,增加客户端的复杂性
- 存在跨域请求,在一定场景下处理相对复杂
- 认证复杂,每一个服务都需要独立认证
- 难以重构,随着项目的迭代,可能需要重新划分微服务,如果客户端直接和微服务 通信,那么重构会难以实施
- 某些微服务可能使用了其他协议,直接访问有一定困难
Zuul 包含了对请求的路由和过滤两个最主要的功能:
- 其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的 基础而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。
- Zuul 和 Eureka 进行整合,将 Zuul 自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获得其他微服务的信息,也即以后的访问微服务都是通过 Zuul 跳转后获得
- 总体来说,Zuul 提供了代理、路由和过滤的功能
二、代码
1. 创建maven quickstart项目
添加
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2. application.yaml
spring:
application:
name: zuul-server
server:
port: 9000
eureka:
client:
service-url:
defaultZone: http://localhost:5000/eureka/
3. 主启动类 @EnableZuulProxy
/**
* @date: 2021/3/7 23:24
* @author: 易学习
* @EnableZuulProxy: 开启网关
*/
@EnableZuulProxy
@SpringBootApplication
public class ApplicationZuul {
public static void main(String[] args) {
SpringApplication.run(ApplicationZuul.class);
}
}
4. 访问测试
三、使用指定地址代替微服务名称
zuul工程的 application.yaml 添加配置
zuul:
routes:
user: # 自定义路由规则的名称,在底层是一个Map的key
serviceId: consumer-service # 目标微服务名称,ZuulRoute类型的一个属性
path: /zuul-user/** # 用来代替目标微服务名称的路径,ZuulRoute类型的一个属性
# /**表示比配多层路径, 如果没有/**则不能匹配后续的多层路径了
效果:使用微服务和自定义的名称都可以访问
http://localhost:9000/zuul-user/remote/search/user/by/name?keyword=11
四、让用户不能通过微服务名称访问
zuul工程的 application.yaml 添加配置
zuul:
routes:
user: # 自定义路由规则的名称,在底层是一个Map的key
serviceId: consumer-service # 目标微服务名称,ZuulRoute类型的一个属性
path: /zuul-user/** # 用来代替目标微服务名称的路径,ZuulRoute类型的一个属性
# /**表示比配多层路径, 如果没有/**则不能匹配后续的多层路径了
#ignored-services: # 忽略指定微服务名称,让用户不能通过微服务名称访问
# - consumer-service
ignored-services: '*' # 忽略所有微服务名称
prefix: /yixuexi # 给访问路径添加统一前缀
配置了前缀访问:
http://localhost:9000/yixuexi/zuul-user/remote/search/user/by/name?keyword=11
注意:如果添加了server.servlet.context-path=/myapp 的话 需要先将/myapp打上
五、使用ZuulFilter拦截过滤请求
/**
* @date: 2021/3/8 16:55
* @author: 易学习
*/
@Component
public class MyZuulFilter extends ZuulFilter {
@Override
public String filterType() {
// 返回当前过滤器的类型,决定当前过滤器在什么时候执行
// pre表示在目标微服务之前执行
// 可选类型包括:pre、route、post、static
String filterType = "pre";
return filterType;
}
@Override
public int filterOrder() {
// 过滤器执行顺序
return 0;
}
/**
* shouldFilter: 应该过滤, 判断当前请求是否进行过滤
* 要过滤:返回true,继续执行run方法
* 不过滤:返回false 直接放行
* @return
*/
@Override
public boolean shouldFilter() {
// 1.获取当前RequestContext对象
RequestContext currentContext = RequestContext.getCurrentContext();
// 2.获取当前请求对象
HttpServletRequest request = currentContext.getRequest();
// 3.获取当前请求要访问的目标地址
String servletPath = request.getServletPath();
// 4.打印
System.out.println("servletPath = " + servletPath);
// 5.当前方法返回值
// true表示应该过滤,下面继续执行run方法
// false表示不应该过滤,直接放行
return false;
}
@Override
public Object run() throws ZuulException {
// 执行具体过滤逻辑
System.out.println("run()");
// 官网文档说,当前实现会忽略这个返回值,所以直接返回null就行
return null;
}
}