网关(Gateway)又称网间连接器、协议转换器。网关在网络层以上实现网络互连,是复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互连,也可以用于局域网互连。 网关是一种充当转换重任的计算机系统或设备。使用在不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。与网桥只是简单地传达信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。微服务的中网关是用来处理外部请求分发到内部服务,用于控制外部流量的分发!
Zuul 是 Netflix OSS 中的一员,是一个基于 JVM 路由和服务端的负载均衡器。提供路由、监控、弹性、安全等方面的服务框架。Zuul 能够与 Eureka、Ribbon、Hystrix 等组件配合使用。
zuulzuul主要功能介绍
动态地将客户端的请求路由到后端不同的服务,做一些逻辑处理,比如聚合多个服务的数据返回。
可以对整个系统的请求进行监控,记录详细的请求响应日志,可以实时统计出当前系统的访问量以及监控状态。
对每一个访问的请求做认证,拒绝非法请求,保护好后端的服务。
压力测试是一项很重要的工作,像一些电商公司需要模拟更多真实的用户并发量来保证重大活动时系统的稳定。通过 Zuul 可以动态地将请求转发到后端服务的集群中,还可以识别测试流量和真实流量,从而做一些特殊处理。
灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。
Zuul大部分功能都是通过过滤器来实现的。Zuul中定义了四种标准过滤器类型,这些过滤器类型对应于请求的典型生命周期。
(1) PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
(2) ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
(3) POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
(4) ERROR:在其他阶段发生错误时执行该过滤器。
zuul还提供了一类内置特殊的过滤器,
(1) StaticResponseFilter:StaticResponseFilter允许从Zuul本身生成响应,而不是将请求转发到源。
(2) SurgicalDebugFilter:SurgicalDebugFilter允许将特定请求路由到分隔的调试集群或主机。
(3) 继承ZuulFilter自定义过滤器
zuul自定义过滤器,
下面主要介绍下ZuulFilter类、
public class AccessUserNameFilter extends ZuulFilter { @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); System.out.println(String.format("%s AccessUserNameFilter request to %s", request.getMethod(), request.getRequestURL().toString())); String username = request.getParameter("username");// 获取请求的参数 if(null != username && username.equals("chhliu")) {// 如果请求的参数不为空,且值为chhliu时,则通过 ctx.setSendZuulResponse(true);// 对该请求进行路由 ctx.setResponseStatusCode(200); ctx.set("isSuccess", true);// 设值,让下一个Filter看到上一个Filter的状态 return null; }else{ ctx.setSendZuulResponse(false);// 过滤该请求,不对其进行路由 ctx.setResponseStatusCode(401);// 返回错误码 ctx.setResponseBody("{\"result\":\"username is not correct!\"}");// 返回错误内容 ctx.set("isSuccess", false); return null; } }
如果前一个过滤器的结果为true,则说明上一个过滤器成功了,需要进入当前的过滤,如果前一个过滤器的结果为false,则说明上一个过滤器没有成功,则无需进行下面的过滤动作了,直接跳过后面的所有过滤器并返回结果
@Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); return (boolean) ctx.get("isSuccess"); }
优先级为0,数字越大,优先级越低
@Override public int filterOrder() { return 0; }
前置过滤器
@Override public String filterType() { return "pre"; } }
filterType
:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
pre:可以在请求被路由之前调用 route:在路由请求时候被调用 post:在route和error过滤器之后被调用 error:处理请求时发生错误时被调用
pom引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
@EnableZuulProxy注解
@EnableZuulProxy @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
配置路由文件
spring.application.name=zuul-test server.port=8080 zuul.routes.test.path=/test/** zuul.routes.test.url=http://c.test.com
指定具体服务路由
zuul.routes.access.path=/access-name/**
上述代码将 access 服务的路由地址配置成了 access-name,也就是当需要访问 access中的接口时,我们可以通过 access-name/接口名 来进行。这其实就是将服务名称变成了我们自定义的名称。** 代表匹配多级接口。
路由前缀
有的时候我们会想在 API 前面配置一个统一的前缀,比如像 http://c.biancheng.net/access/login 这样登录接口,如果想将其变成 http://c.biancheng.net/rest/access/login,即在每个接口前面加一个 rest,此时我们就可以通过 Zuul 中的配置来实现:
zuul.prefix=/rest
本地跳转
Zuul 的 API 路由还提供了本地跳转功能,通过 forward 就可以实现。
zuul.routes.fsh-substitution.path=/api/** zuul.routes.fsh-substitution.url=forward:/local
当我们想在访问 api/1 的时候会路由到本地的 local/1 上去,就可以参照上述代码实现。local 是本地接口需要我们自行添加,因此我们要建一个 Controller,代码如下所示。
@RestController public class LocalController { @GetMapping("/local/{id}") public String local(@PathVariable String id) { return id; } }
Configuration public class FilterConfig { @Bean public AccessUserNameFilter accessFilter() { return new AccessUserNameFilter(); } }
如何禁用自定义过滤器
有的场景下,我们需要禁用过滤器,此时可以采取下面的两种方式来实现:
因为zuul2.0连续跳票和zuul1的性能表现不是很理想,所以催生了spring团队开发了Gateway项目。下篇介绍Spring cloud gateway
欢迎关注公众号! 公众号回复:
入群
,扫码加入我们交流群