文章目录
1. 环境准备
推荐本篇文章在《SpringCloud之Gateway使用篇》读,因为我们要使用它之前或者之后的环境。
当然可以到github上面访问项目代码:链接,直接拉下来使用。
这里我们介绍下环境
spring-cloud-parent (父工程,定义了springcloud的版本以及通用依赖)
----spring-cloud-eureka-server (Eureka Server 集群,端口9090,9091)
----spring-cloud-order-service-provider(订单服务,也是服务提供者,端口7070,7071)
----spring-cloud-user-service-consumer(用户服务,调用订单服务,端口8080,8081)
----spring-cloud-zuul-server(zuul网关服务,端口8030)
2.使用
2.1 最基础使用
2.1.1 新建zuul服务
在父工程spring-cloud-parent 新创建module spring-cloud-zuul-server
2.1.1.1 pom文件
添加eureka 客户端依赖 与zuul网关依赖
<dependencies>
<!--eureka 客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--zuul 网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
zuul其实使用的springmvc ,而不像gateway一样使用webflux
2.1.1.2 application配置文件
这里暂时只是配置了Eureka。
server:
port: 8030
spring:
application:
name: spring-cloud-zuul-server
#eureka 配置
eureka:
client:
service-url:
# eureka server url
defaultZone: http://EurekaServerA:9090/eureka,http://EurekaServerB:9091/eureka
register-with-eureka: true
fetch-registry: true
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
2.1.1.3 主启动类
需要在主启动类上面添加@EnableZuulProxy 注解,表示启用zuul
2.1.1.4 启动测试
分别启动Eureka Server 集群端口9090与9091,订单服务两个实例端口7070与7071,用户服务 一个实例8080,最后启动咱们这个zuul网关服务8030
postman或者浏览器访问:
http://127.0.0.1:8030/spring-cloud-user-service-consumer/user/data/getTodayStatistic/100
*** 注意:咱们在url中添加了用户服务服务名,因为咱们并没有在配置文件中配置路由规则***
多访问几次,发现有hystrix 的timeout
这个是因为我们没有配置这个hystrix熔断器,这我们后面再配置。
2.2 路由介绍
1.URL 路由,是直接写死在配置上的,不能进行负载均衡,可以是ip,也可以是域名,例如下面这种配置:
zuul:
routes:
baidu-router:
path: /baidu
url: http://www.baidu.com
2.第二种就是基于ribbon实现配置多个url来进行负载均衡,我们需要在url配置一个serivecId,然后使用这个serivceId配置ribbon的servers,这个servers可以配置多个,实际上还是使用了ribbon来做的负载均衡,就像下面这种配置
zuul:
routes:
baidu-router:
path: /user/**
url: spring-cloud-user-service-consumer
spring-cloud-user-service-consumer:
ribbon:
list-of-servers: http://127.0.0.1:8080
3.这种就是基于Eureka 来做的动态路由,我们需要在 Zuul 中集成 Eureka,在路由转发时可以转发到 Eureka 中注册的服务上,这样就很方便了,不需要我们去关心服务的上下线,我们只需要在router中配置serviceId与path就可以了,这种方式是使用最多的。
就像这种方式:
zuul:
routes:
user-service-consumer-router:
path: /user/**
service-id: spring-cloud-user-service-consumer
这个service-id就是这个注册到Eureka server 中的服务名,而这个path就是头匹配的。这种方式会默认给你去掉这个path,也就是去掉这个前缀,所以我请求的时候需要加个前缀,然后按照前缀匹配。比如说我这里请求spring-cloud-user-service-consumer的某个接口,/user/data/getTodayStatistic/100,然后我在使用zuul来路由的时候就需要就需要加上path里面这个user前缀,/user/user/data/getTodayStatistic/100,就变成这个样子了,当然你可以不开启这种去掉前缀的操作。使用配置 strip-prefix: false就可以了,例如下面这段配置:
zuul:
routes:
user-service-consumer-router:
path: /user/**
service-id: spring-cloud-user-service-consumer
strip-prefix: false
这里我请求的时候就不需要加前缀了。
现在还有个问题就是 使用service-id这个前缀还是能访问到的
这里我们就需要配置一个ignored-services,例如下面的配置,这样配置只是单个的,如果想把所有服务的名字都屏蔽掉就要使用“*”号了。
zuul:
routes:
user-service-consumer-router:
path: /user/**
service-id: spring-cloud-user-service-consumer
strip-prefix: false
ignored-services: spring-cloud-user-service-consumer
配置好了就ok了,不可以访问了。
我们还有一个配置,就是在所有的router前面添加一个前缀,可以使用zuul.prefix来配置
zuul:
routes:
user-service-consumer-router:
path: /user/**
service-id: spring-cloud-user-service-consumer
strip-prefix: false
ignored-services: spring-cloud-user-service-consumer
prefix: /beijing
2.3 过滤器介绍
我们可以先来看下这个zuul的过滤器一个生命周期图,然后咱们再来说这个zuul过滤器的分类
我们可以很清晰的看到,当我们请求来的时候,先到pre 类型的过滤器,接着就是routing过滤器,接着就是到了我们真实的服务器,真实服务器处理完成,响应返回到网关的时候 就到了post 类型的过滤器。
过滤器类型 | 解释 |
---|---|
pre | 在请求 被路由前调用,适用于身份认证的场景,ip黑白名单等等 |
route | 在请求被调用时执行,这个可以通过自定义一些规则进行灰度发布 |
post | 这个是真实服务器响应回来的时候或者error过滤器执行完的时候调用,添加响应头,记录响应日志等应用场景 |
error | 这个是请求过程中异常的时候调用,可以用来统一记录错误信息 |
我这里定义一个pre的过滤器,来模拟一下黑白名单
@Component
public class BlackListFilter extends ZuulFilter {
private static List<String> blackList;
static {
// 模拟黑名单
blackList=new ArrayList<>();
blackList.add("127.0.0.1");
}
// filter 类型
@Override
public String filterType() {
return "pre";
}
// filter排序
@Override
public int filterOrder() {
return 0;
}
// 是否启用filter
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
// 获取context
RequestContext currentContext = RequestContext.getCurrentContext();
// 获取requst
HttpServletRequest request = currentContext.getRequest();
// 客户端地址
String remoteHost = request.getRemoteHost();
if (blackList.contains(remoteHost)){
currentContext.set("isSuccess", false);
currentContext.setSendZuulResponse(false);
currentContext.setResponseBody("非法请求");
currentContext.getResponse().setContentType("application/json; charset=utf-8");
}
return null;
}
}
我们请求一下,可以看到被拦截下了: