目录
一. 前言
Zuul 是 spring cloud
中的微服务网关API Gateway
,是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求、鉴权、监控、缓存、限流等功能
二. Zuul网关
1. 引入依赖
在pom文件中引入依赖,可以通过idea快速创建 start.spring.io快速创建网关项目
<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.yml 配置
server:
port: 9000
spring:
application:
name: api-gateway
#指定注册中心地址
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
# zuul 网关
zuul:
routes:
myuserserver: #这里是路由id,随意写
path: /userserver/** #这里是映射路径
serviceId: user-server #配置转发的微服务名称
# 另一种路径映射配置方式
# order-service:服务id /os/**:映射路径
#zuul:
# routes:
# order-service: /os/**
3. 添加注解
加上@EnableZuulProxy
注解,开启Zuul的功能。代码如下:
@EnableCircuitBreaker
注解默认集成了断路器@EnableCircuitBreaker
@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
4. 自定义路由转发
order-service 为服务id(对应服务在注册中心的名称),以/os/**
开头的访问路径都会被分发到order-service服务中
zuul:
routes:
order-service: /os/**
5. 环境隔离配置
zull 网关及时不自定义路由转发规则 也有默认访问规则http://gateway:port/service-id/xx
,如果不想让默认的服务访问路径对外暴露,我们可以进行如下配置 ignored-patterns
忽略访问路径
zuul:
ignored-patterns:
- /*-service/api/v1/**
ignored-patterns
配置为正则表达式
三. 自定义拦截器(登录鉴权)
新建 filter 包,新建一个类实现ZuulFilter
并重写方法,在类顶部加注解 @Compoent
以下是简单的 登录鉴权演示,拦截器共四种类型(pre
,post
,route
,error
),我们这里选择 pre
前置过滤器
@Component
public class LoginFilter extends ZuulFilter{
/* 过滤器类型,可选值有 pre、route、post、error */
@Override
public String filterType() {
return PRE_TYPE;
}
/* 过滤器的执行顺序,数值越小,优先级越高 */
@Override
public int filterOrder() {
// 过滤器执行顺序,值越小 越先执行
return 4;
}
/* 是否执行该过滤器,true 为执行,false 为不执行,这个也可以利用配置中心来实现,达到动态的开启和关闭过滤器 */
@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
// 对指定路径进行过滤,返回true后 会进入到 run 方法执行业务逻辑
if ("/od/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())){
return true;
}
return false;
}
/* 业务逻辑,本次是判断请求的url是否带有token,没有则通过设置 ctx.setSendZuulResponse(false),
告诉 Zuul 不需要将当前请求转发到后端的服务了,不需要继续往下走了,通过setResponseBody 返回数据给客户端 */
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String token = request.getHeader("token");
if (StringUtils.isBlank(token)){
token = request.getParameter("token");
}
if (StringUtils.isBlank(token)){
//是否继续往下走
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
return null;
}
}
四. 网关限流配置(令牌桶)
在filter包中新建RateLimiterFilter
类并继承ZuulFilter
接口
@Component
public class RateLimiterFilter extends ZuulFilter {
/* 定义一个令牌桶,每秒产生1000个令牌,即每秒最多处理1000个请求 */
private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);
/* 过滤器类型,可选值有 pre、route、post、error */
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return -4;
}
@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
if ("/od/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())){
return true;
}
return false;
}
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
/**
* tryAcquire() 只要能够马上获致到1个令牌,则返回true,不阻塞
* tryAcquire(5, 3, TimeUnit.SECONDS) 在3秒钟内可以获取到5个令牌,则返回true,不阻塞
* acquire(5) 获取到5个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
* acquire() 获取到1个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
*/
if (!RATE_LIMITER.tryAcquire()) {
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
}
return null;
}
}