SpringCloud 学习之 Zuul

Zuul又是啥

Zuul是Netflix开发的微服务网关,又是Netflix…真牛批!作为一个中间层吧,客户端通过网关去访问服务,这难道就是传说中的解耦???

路由配置

简单使用

在原来的工程里新建一个module,pom里面加入Zuul的依赖

1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>

在启动类上加上@EnableZuulProxy,修改配置文件

1
2
3
4
5
6
7
server:
port: 10001
zuul:
routes:
provide:
path: /provide/**
url: http://127.0.0.1:8080

稍微记一下,routes是一个路由列表,provide是路由id,path是映射路径,url是转发路径
这条配置就相当于所有的 /provide/ 请求都会被转发到8080端口的服务去

然后又是老问题,路径又写死了- -,怎么办…找eureka咯

简单使用的升级

先加eureka的依赖,之前的版本的artifactId好像是spring-cloud-starter-eureka,但是我现在用的比较新的这个会找不到,所以在pom里面加

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

然后启动类上加上@EnableDiscoveryClient,老套路了都,再改配置文件

1
2
3
4
5
6
7
8
9
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
zuul:
routes:
provide:
path: /provide/**
serviceId: provide

就是加上eureka的配置,然后把url改成用serviceId,重新启动效果是一样的,zuul里面还集成hystrix和ribbon,我的电脑好像比较奇葩,访问的时候报错,超时了!本地都能超时我也是服了!
如果超时的话,加点配置就好了

1
2
3
4
5
6
7
8
9
10
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000
ribbon:
ConnectTimeout: 500
ReadTimeout: 3000

跟之前说的feign的配置差不多吧
(在这小声BB下,我发现我智障- -忘记重启provide服务,睡1s的代码还在所以超时了…)
接下来再简化下配置

1
2
3
zuul:
routes:
provide: /provide/**

直接用serviceId来当routeId,连path都不用写了,舒服~

默认配置

启动custom服务,访问 http://localhost:10001/custom/msg 然后就会发现根本没配置他也访问到了,真是神奇…默认配置太方便了- -
但是有些不想暴露的服务他也暴露了,这就不行了,加下配置,假设custom服务不想暴露

1
2
3
4
5
zuul:
routes:
provide: /provide/**
ignored-services:
- custom

ignored-services 配置不想暴露的服务列表

前缀配置

匹配路由的前缀是可以去掉的- -但是我觉得不好,所以就不记了,知道就好了
记一下全局的的前缀 prefix

过滤器

Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。

ZuulFilter

ZuulFilter是过滤器的顶级父类。在这里我们看一下其中定义的4个最重要的方法:

1
2
3
4
5
6
7
8
9
10
public abstract ZuulFilter implements IZuulFilter{

abstract public String filterType();

abstract public int filterOrder();

boolean shouldFilter();// 来自IZuulFilter

Object run() throws ZuulException;// IZuulFilter
}
  • shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
  • run:过滤器的具体业务逻辑。
  • filterType:返回字符串,代表过滤器的类型。包含以下4种:
    • pre:请求在被路由之前执行
    • routing:在路由请求时调用
    • post:在routing和errror过滤器之后调用
    • error:处理请求时发生错误调用
  • filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。

过滤器执行生命周期:

这张是Zuul官网提供的请求生命周期图,清晰的表现了一个请求在各个过滤器的执行顺序。

1525681866862

  • 正常流程:
    • 请求到达首先会经过pre类型过滤器,而后到达routing类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。
  • 异常流程:
    • 整个过程中,pre或者routing过滤器出现异常,都会直接进入error过滤器,再error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
    • 如果是error过滤器自己出现异常,最终也会进入POST过滤器,而后返回。
    • 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和routing不同的时,请求不会再到达POST过滤器了。

所有内置过滤器列表:

1525682427811

使用场景

场景非常多:

  • 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
  • 异常处理:一般会在error类型和post类型过滤器中结合来处理。
  • 服务调用时长统计:pre和post结合使用。

自定义过滤器

接下来我们来自定义一个过滤器,模拟一个登录的校验。基本逻辑:如果请求中有access-token参数,则认为请求有效,放行。

定义过滤器类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Component
public class LoginFilter extends ZuulFilter{
@Override
public String filterType() {
// 前置拦截
return FilterConstants.PRE_TYPE;
}

@Override
public int filterOrder() {
// 顺序设置为1
return 0;
}

@Override
public boolean shouldFilter() {
// 返回true,代表过滤器生效。
return true;
}

@Override
public Object run() throws ZuulException {
// 获取当前请求上下文
RequestContext currentContext = RequestContext.getCurrentContext();
// 获取request
HttpServletRequest request = currentContext.getRequest();
// 假装获取token
String token = request.getHeader("token");
// 假装判断token
if(token==null || "".equals(token.trim())){
// 校验没过
currentContext.setSendZuulResponse(false);
currentContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
currentContext.setResponseBody("unauthorized");
}
return null;
}
}

啊好烦,怎么这么多!!!!不想学了啊啊啊啊啊啊啊